LoginSignup
0
1

More than 3 years have passed since last update.

UIが出すNotificationを複数ウインドウ間で処理する : Swift

Last updated at Posted at 2021-03-01

概要

ドキュメントベースのアプリケーションを作っていてNSScrollViewdocumentVisibleRectを継続的に取得しようとしたら突っ掛かった所があって他のUIに応用ができると思ったので書きます。

解決方法

NSUserInterfaceItemIdentifieruuidを含めた状態でNotificationを受け取る。

やろうとした事

普通にNotificationを使う。

まず、NSScrollViewがスクロールされている時に出されるNSScrollViewNSNotification.Name型のdidLiveScrollNotificationを使って

class ViewController: NSViewController {
    //...中略
    override func viewDidLoad() {
        super.viewDidLoad()
        //...
        let scrollView = NSScrollView(frame: NSMakeRect(0, 0, 100, 100))
        scrollView.identifier = NSUserInterfaceItemIdentifier("ScrollView")
        //...
        NotificationCenter.default.addObserver(self, selector: #selector(ScrollViewLiveScroll(_:)), name: NSScrollView.didLiveScrollNotification, object: nil)
    }

    @objc private func ScrollViewLiveScroll(_ notification: Notification){
        guard let scrollView = notification.object as? NSScrollView else { return }
        if scrollView.identifier?.rawValue == "ScrollView" {
            print(scrollView.documentVisibleRect)
        }
    }
}

しかし、ドキュメントベースのアプリで、scrollViewidentifierが同じなので、ユーザーが作った他のウインドウでのイベントも受け取ってしまう。

KVO (Key-Value-Observing)を使ってscrollView.documentVisibleRectの変更を監視する。

これもしかし、値が=で代入された時は通知されるが、UI内部で変化するdocumentVisibleRectの変化は受け取ってくれないらしい?ので無理。

KVOで出来る方法を知っている方がいたら教えてください。

NotificationCenterを新たに宣言してNotification

クラス内でNotificationCenterを新たに宣言することによって重複した通知を受け取らないようにする。

しかし、UIがNotificationCenter.defaultNotificationを出すことは変えられないので、受け取る側のNotificationCenterを変えてしまっては受け取れない。

解決した方法

scrollViewidentifierが同じなら変えればいいということで、uuidで一意なIDを生成して、そのクラスがインスタンス化された時毎に違う Identifier を生成すればできる!ということで

class ViewController: NSViewController {
    let uuid = UUID()//ここで
    //...中略
    override func viewDidLoad() {
        super.viewDidLoad()
        //...
        let scrollView = NSScrollView(frame: NSMakeRect(0, 0, 100, 100))
        scrollView.identifier = NSUserInterfaceItemIdentifier("ScrollView\(\(uuid.uuidString))")
        //...
        NotificationCenter.default.addObserver(self, selector: #selector(ScrollViewLiveScroll(_:)), name: NSScrollView.didLiveScrollNotification, object: nil)
    }

    @objc private func ScrollViewLiveScroll(_ notification: Notification){
        guard let scrollView = notification.object as? NSScrollView else { return }
        if scrollView.identifier?.rawValue == "ScrollView\(\(uuid.uuidString))" {
            print(scrollView.documentVisibleRect)
        }
    }
}

identifierは"UserInterface"には使えるので、NSScrollView以外にも応用できます

余談ですが、この時のidentifierは、

The slash (/), backslash (\), or colon (:) characters are reserved and must not be used in your custom identifiers. Similarly, Apple reserves all identifiers beginning with an underscore (_) character.

https://developer.apple.com/documentation/appkit/nsuserinterfaceitemidentification/1396829-identifierより

(/),(),(:)は使えず、また、(_)はappleが先頭を予約しているので使えません。

参考

uuidの参考

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1