2017-07-13 33 views
3

语言的可选功能:迅捷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又一个Notification。所以在这种情况下,上面的代码会导致崩溃。

但是,如果我这样做

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

     self.listenToFoo() 
    } 
} 

extension GodzillaViewController: SomeProtocol { 
    func foo(_ notification: Notification) { 
     print("lol") 
    } 
} 

因为foo(_:)没有崩溃创建不是可有可无的了。

:此代码是不可能的#selector(self.foo?(_:))

问题:是否有可能有一个选择调用的可选功能没有崩溃的应用程序?

回答

4

如果我在那里你我会做一个完整的,迅速的协议,像这样:

// 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) 
     } 
    } 
} 

正如你所看到的,做它像这样有很多好处:

  1. 你有斯威夫特只代码(no @objc)
  2. 通过添加foo的默认实现,您使该功能成为可选项。
  3. 您的通知仍然可以调用foo没有崩溃,因为它会在必要时去的默认实现
  4. ,你甚至可以添加一些代码的默认方法,如果你仍然想要做的事!

UPDATE

您可以在我用一个使用了闭相反,原因是#selector仍需要功能暴露于@objc不同addObserver功能listenToFoo()功能看和关闭不:

func addObserver(forName name:NSNotification.Name ?, object obj:Any ?, queue:OperationQueue?,使用块:@escaping(通知) - >无效) - > NSObjectProtocol

+0

@Hamish是正确的,你不能谁不暴露于对象 - –

+0

函数使用通知中心@Hamish你说得对,我更新了使用不需要@objc的不同'addObserver'函数的答案!谢谢 – Thomas

+1

@ZonilyJame'#选择器'这样做的方式是需要一种方法暴露给ObjC。当然还有其他的可能性,比如我改变它的那个,或者如果你真的想使用选择器出于某种原因,你应该看看Swift变体,它可以像这样工作,而不是'Selector(“foo(_ :)”)' – Thomas