UIResponder.keyboardDidShowNotification が他のアプリに切替した時にも通知される問題

iOS アプリでキーボードが表示されたイベントを知りたい時に UIResponder.keyboardDidShowNotification を通知を受ける。

コードは以下のたとえば下のようになる。

import UIKit
import os

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let textField = UITextField(frame: CGRect(x: 0, y: 0, width: 150, height: 34))
        textField.center = self.view.center
        textField.borderStyle = .roundedRect
        self.view.addSubview(textField)
        
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(keyboardDidShow),
                                               name: UIResponder.keyboardDidShowNotification,
                                               object: nil)
        
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(keyboardWillHide),
                                               name: UIResponder.keyboardWillHideNotification,
                                               object: nil)
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.view.endEditing(true)
    }
    
    @objc private func keyboardDidShow(notification: NSNotification) {
        // キーボードが表示になった時の通知
    }
    
    @objc private func keyboardWillHide(notification: NSNotification) {
        // キーボードが非表示になった時の通知
}


ただ、これだと「キーボードを開いている他のアプリ」に切替した時も、キーボード表示の通知がきてしまう。

例えば、以下のようにキーボードを開いている状態の Safari を開いた時などだ。

f:id:daisuke-t-jp:20200322142552p:plain:w300



このような問題があるので、どうやって自分のアプリ/他のアプリのキーボード通知を見分けるのか調べると、以下のドキュメントがあった。

https://developer.apple.com/documentation/uikit/uiresponder/1621603-keyboardislocaluserinfokey

keyboardIsLocalUserInfoKey

The key for an NSNumber object containing a Boolean that identifies whether the keyboard belongs to the current app. With multitasking on iPad, all visible apps are notified when the keyboard appears and disappears. The value of this key is true for the app that caused the keyboard to appear and false for any other apps.

つまり UIResponder.keyboardIsLocalUserInfoKey の値が true なら自分のアプリ、false なら他のアプリ、ということになる。

実際に下のようなコードで試すと、期待する結果が得られた。

@objc private func keyboardDidShow(notification: NSNotification) {
        guard let isLocalUserInfoKey = notification.userInfo?[UIResponder.keyboardIsLocalUserInfoKey] as? NSNumber else { return }
        
        print("keyboardDidShow ", separator: "", terminator: "")

        if isLocalUserInfoKey.boolValue {
            print("-> My app event")
        }
        else {
            print("-> Other app event")
        }
    }