Ios Swift使协议扩展成为通知观察员 让我们考虑下面的代码: protocol A { func doA() } extension A { func registerForNotification() { NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardDidShow:"), name: UIKeyboardDidShowNotification, object: nil) } func keyboardDidShow(notification: NSNotification) { } }
现在来看一个UIViewController子类,它实现了:Ios Swift使协议扩展成为通知观察员 让我们考虑下面的代码: protocol A { func doA() } extension A { func registerForNotification() { NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardDidShow:"), name: UIKeyboardDidShowNotification, object: nil) } func keyboardDidShow(notification: NSNotification) { } },ios,swift,swift2,protocol-extension,Ios,Swift,Swift2,Protocol Extension,现在来看一个UIViewController子类,它实现了: class AController: UIViewController, A { override func viewDidLoad() { super.viewDidLoad() self.registerForNotification() triggerKeyboard() } func triggerKeyboard() { // Some code that
class AController: UIViewController, A {
override func viewDidLoad() {
super.viewDidLoad()
self.registerForNotification()
triggerKeyboard()
}
func triggerKeyboard() {
// Some code that make key board appear
}
func doA() {
}
}
但令人惊讶的是,这会因为一个错误而崩溃:
keyboardDidShow::发送到实例的选择器无法识别
0x7fc97adc3c60
那么我应该在视图控制器本身中实现观察器吗?它不能留在分机里吗
下面的事情已经尝试过了
制作一个类协议。
将keyboardDidShow作为签名添加到协议本身
protocol A:class {
func doA()
func keyboardDidShow(notification: NSNotification)
}
为了避免崩溃,在使用协议的Swift类中实现observer方法 实现必须在Swift类本身中,而不仅仅是协议扩展,因为选择器总是引用Objective-C方法,协议扩展中的函数不能用作Objective-C选择器。但是,如果Swift类继承自Objective-C类,则Swift类中的方法可用作Objective-C选择器 另外,在Xcode 7.1中,
self
在addObserver
调用中将其指定为观察者时,必须向下转换为AnyObject
protocol A {
func doA()
}
extension A {
func registerForNotification() {
NSNotificationCenter.defaultCenter().addObserver(self as! AnyObject,
selector: Selector("keyboardDidShow:"),
name: UIKeyboardDidShowNotification,
object: nil)
}
func keyboardDidShow(notification: NSNotification) {
print("will not appear")
}
}
class ViewController: UIViewController, A {
override func viewDidLoad() {
super.viewDidLoad()
self.registerForNotification()
triggerKeyboard()
}
func triggerKeyboard(){
// Some code that makes the keyboard appear
}
func doA(){
}
func keyboardDidShow(notification: NSNotification) {
print("got the notification in the class")
}
}
通过实现
NSNotificationCenter
的较新的-addObserverForName:object:queue:usingBlock:
方法并直接调用该方法,我解决了类似的问题
extension A where Self: UIViewController {
func registerForNotification() {
NSNotificationCenter.defaultCenter().addObserverForName(UIKeyboardDidShowNotification, object: nil, queue: nil) { [unowned self] notification in
self.keyboardDidShow(notification)
}
}
func keyboardDidShow(notification: NSNotification) {
print("This will get called in protocol extension.")
}
}
此示例将导致在协议扩展中调用
keyboardDidShow
。在Swift中使用选择器要求您的具体类必须从NSObject继承。要在协议扩展中强制执行此操作,应使用where
。例如:
protocol A {
func doA()
}
extension A where Self: NSObject {
func registerForNotification() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardDidShow:"), name: UIKeyboardDidShowNotification, object: nil)
}
func keyboardDidShow(notification: NSNotification) {
}
}
除了詹姆斯·保兰托尼奥的回答。可以使用关联对象实现
unregisterForNotification
方法
var指针:UInt8=0
扩展NSObject{
var userInfo:[字符串:任意]{
得到{
如果让userInfo=objc_getAssociatedObject(self,&指针)作为?[字符串:Any]{
返回用户信息
}
self.userInfo=[String:Any]()
返回self.userInfo
}
设置(新值){
objc_setAssociatedObject(self、指针、newValue、.objc_ASSOCIATION_RETAIN)
}
}
}
协议A{}
扩展名A,其中Self:UIViewController{
var默认值:NotificationCenter{
得到{
return NotificationCenter.default
}
}
func键盘显示(通知:通知){
//键盘确实显示了
}
func registerForNotification(){
userInfo[“didShowObserver”]=默认值。addObserver(forName:.UIKeyboardDidShow,对象:nil,队列:nil,使用:keyboardDidShow)
}
func unregisterForNotification(){
如果让didShowObserver=userInfo[“didShowObserver”]作为NSObjectProtocol{
默认值。removeObserver(didShowObserver,名称:.UIKeyboardDidShow,对象:nil)
}
}
}
我使用NSObjectProtocol
解决了它,如下所示
@objc protocol KeyboardNotificaitonDelegate: NSObjectProtocol {
func keyboardWillBeShown(notification: NSNotification)
func keyboardWillBeHidden(notification: NSNotification)
}
extension KeyboardNotificaitonDelegate {
func registerForKeyboardNotifications() {
//Adding notifies on keyboard appearing
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeShown(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
func deregisterFromKeyboardNotifications() {
//Removing notifies on keyboard appearing
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
}
我过去也尝试过类似的方法,但我发现Swift的协议扩展不能与Objective-C协议和类一起工作,我很困惑
扩展A{}
???您正在谈论的是扩展控制器{}
您只需要将参数添加到方法或从选择器的name@MidhunMP . 是的,它是扩展名A{}
。Swift 2以后的新功能。这就是所谓的协议扩展。它甚至可以为协议方法添加默认功能。该方法是func keyboardDidShow(通知:NSNotification)
,它与选择器(“keyboardDidShow:”)
非常明显,但没有想到它-cudos!伟大的发现!错过了那一个:)你如何移除观察者?假设我想要一个函数来移除观察器(在扩展中也是如此),然后从deinit@tolkiana您还可以添加一个func unregisterForNotification()
@JamesPaolantonio您可以更具体地说明如何实现unregisterForNotification
方法吗?要删除观察者,您需要存储addObserverForName
的返回值,但这在扩展上是不可能的