#概要
ドキュメントベースのアプリケーションを作っていてNSScrollView
のdocumentVisibleRect
を継続的に取得しようとしたら突っ掛かった所があって他のUIに応用ができると思ったので書きます。
###解決方法
NSUserInterfaceItemIdentifier
にuuid
を含めた状態でNotification
を受け取る。
##やろうとした事
####普通にNotification
を使う。
まず、NSScrollView
がスクロールされている時に出されるNSScrollView
のNSNotification.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)
}
}
}
しかし、ドキュメントベースのアプリで、scrollView
のidentifier
が同じなので、ユーザーが作った他のウインドウでのイベントも受け取ってしまう。
####KVO (Key-Value-Observing)
を使ってscrollView.documentVisibleRect
の変更を監視する。
これもしかし、値が=
で代入された時は通知されるが、UI内部で変化するdocumentVisibleRect
の変化は受け取ってくれないらしい?ので無理。
KVO
で出来る方法を知っている方がいたら教えてください。
####NotificationCenter
を新たに宣言してNotification
クラス内でNotificationCenter
を新たに宣言することによって重複した通知を受け取らないようにする。
しかし、UIがNotificationCenter.default
でNotification
を出すことは変えられないので、受け取る側のNotificationCenter
を変えてしまっては受け取れない。
##解決した方法
scrollView
のidentifier
が同じなら変えればいいということで、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.
(/),(),(:)は使えず、また、(_)はappleが先頭を予約しているので使えません。
#参考
uuid
の参考