Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 如何使用选择器和NotificationCenter调用可选函数_Ios_Swift_Selector_Swift Protocols - Fatal编程技术网

Ios 如何使用选择器和NotificationCenter调用可选函数

Ios 如何使用选择器和NotificationCenter调用可选函数,ios,swift,selector,swift-protocols,Ios,Swift,Selector,Swift Protocols,语言:Swift 3 IDE:XCode 8.3.2(8E2002) 我有一个带有可选功能的协议foo @objc protocol SomeProtocol { @objc optional func foo(_ notification: Notification) } extension SomeProtocol { func listenToFoo() { NotificationCenter.default.addObserver(self, sele

语言:Swift 3

IDE:XCode 8.3.2(8E2002)

我有一个带有可选功能的协议
foo

@objc protocol SomeProtocol {
    @objc optional func foo(_ notification: Notification)
}

extension SomeProtocol {
    func listenToFoo() {
        NotificationCenter.default.addObserver(self, selector: #selector(self.foo(_:)), name: NSNotification.Name(rawValue: "UltimateNotificationKeyLOL"), object: nil)
    }
}
如果我将此代码扩展到,请说一个
UIViewController

class CrashingViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        self.listenToFoo()
    }
}

extension CrashingViewController: SomeProtocol { } 
现在问题来了,因为
foo
是一个可选函数,如果任何人使用键
NSNotification.Name(rawValue:“UltimateNotificationKeyLOL”)
发送
通知,应用程序将崩溃,因为我还没有实现
foo
。因此,在这种情况下,上述代码将导致崩溃

但是如果我这样做

class GodzillaViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        self.listenToFoo()
    }
}

extension GodzillaViewController: SomeProtocol {
    func foo(_ notification: Notification) {
        print("lol")
    }
} 
由于
foo(:)
不再是可选的,因此不会创建崩溃

同样:此代码不可能
#选择器(self.foo?(:)


问题:有没有可能让选择器调用一个可选函数而不使应用程序崩溃?

如果我在你那里,我会像这样制定一个完整的swift协议:

// Protocol declaration
protocol SomeProtocol {
    func foo(_ notification: Notification)
}

// Provide default implementation for optional methods of SomeProtocol
extension SomeProtocol {
    func foo(_ notification: Notification) {}
}

// Extend SomeProtocol with additional methods
extension SomeProtocol {
    func listenToFoo() {
        NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "UltimateNotificationKeyLOL"), object: nil, queue: nil) { (notification) in
            self.foo(notification)
        }
    }
}
如您所见,这样做有多重好处:

  • 您只有Swift代码(无@objc)
  • 通过添加
    foo
    的默认实现,您使函数成为可选的
  • 您的通知仍然可以调用
    foo
    ,而不会崩溃,因为它将在必要时转到默认实现
  • 如果您仍然想做一些事情,您甚至可以向默认方法添加一些代码 更新

    您可以在
    listenToFoo()
    函数中看到,我使用了一个不同的
    addObserver
    函数,该函数使用了闭包,原因是#selector仍然要求将函数公开给@objc,而闭包没有:

    func addObserver(forName名称:NSNotification.name?,对象对象对象:Any?,队列:OperationQueue?,使用块:@escaping(Notification)->Void)->NSObjectProtocol


    @Hamish是正确的,您不能对未暴露于Obj的函数使用NotificationCenter-C@Hamish你说得对,我更新了答案,使用了一个不需要@objc的不同的
    addObserver
    函数!Thanks@ZonilyJame执行此操作的
    #选择器
    方法需要将方法公开给ObjC。当然还有其他的可能性,比如我把它改成的,或者如果你真的想出于某种原因使用选择器,你应该看看Swift变体,它的工作原理是这样的
    Selector(“foo(:)”)
    ohhh,根据你的代码,我找到了一个我想去的解决方案。我还认为,
    addObserver(……block:)
    仅在上面的iOS 10/9中受支持,看起来他们改变了它。但这也是一个很好的实现,它没有告诉我如何使用@objc