25

次のコードを考えてみましょう。

protocol A {
    func doA()
}

extension A {
  func registerForNotification() {
      NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardDidShow:"), name: UIKeyboardDidShowNotification, object: nil)
  }

  func keyboardDidShow(notification: NSNotification) {

  }
}

次に、A を実装する UIViewController サブクラスを見てください。

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 に送信されました

ビューコントローラー自体にオブザーバーを実装する必要がありますか? エクステに残らないの?

以下のことはすでに試しました。

A をクラス プロトコルにします。署名としてプロトコル自体に keyboardDidShow を追加します。

protocol A:class {
   func doA()
   func keyboardDidShow(notification: NSNotification)
}
4

5 に答える 5

3

ジェームズ・パオラントニオの答えに加えて。関連付けられたunregisterForNotificationオブジェクトを使用してメソッドを実装できます。

var pointer: UInt8 = 0

extension NSObject {
    var userInfo: [String: Any] {
        get {
            if let userInfo = objc_getAssociatedObject(self, &pointer) as? [String: Any] {
                return userInfo
            }
            self.userInfo = [String: Any]()
            return self.userInfo
        }
        set(newValue) {
            objc_setAssociatedObject(self, &pointer, newValue, .OBJC_ASSOCIATION_RETAIN)
        }
    }
}

protocol A {}
extension A where Self: UIViewController {

    var defaults: NotificationCenter {
        get {
            return NotificationCenter.default
        }
    }

    func keyboardDidShow(notification: Notification) {
        // Keyboard did show
    }

    func registerForNotification() {
        userInfo["didShowObserver"] = defaults.addObserver(forName: .UIKeyboardDidShow, object: nil, queue: nil, using: keyboardDidShow)
    }

    func unregisterForNotification() {
        if let didShowObserver = userInfo["didShowObserver"] as? NSObjectProtocol {
            defaults.removeObserver(didShowObserver, name: .UIKeyboardDidShow, object: nil)
        }
    }
}
于 2017-03-10T11:47:35.650 に答える
1

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) {

  }
}
于 2016-01-19T04:54:38.257 に答える
1
于 2015-10-24T23:00:02.720 に答える
0

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)
}
}
于 2017-08-14T05:43:35.173 に答える