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

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

###解決方法
`NSUserInterfaceItemIdentifier`に`uuid`を含めた状態で`Notification`を受け取る。
##やろうとした事
####普通に`Notification`を使う。
まず、`NSScrollView`がスクロールされている時に出される`NSScrollView`の`NSNotification.Name`型の`didLiveScrollNotification`を使って

```swift
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 を生成すればできる！ということで

```swift
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](https://developer.apple.com/documentation/appkit/nsuserinterfaceitemidentification/1396829-identifier)より

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

https://qiita.com/addson/items/57e960a556161230de74