Protocolを利用したNotificationCenter

# はじめに
14日目は、（株）スマートテック・ベンチャーズの串田(@eKushida)が担当します。

Swift3バージョンアップに伴い、
NSNotificationCenterのクラス名が
NotificationCenterに変更になりましたね。

他にも下記のメソッドに変更が入っています。

## 変更点
|機能| Swift2 | Swift3 |
|---|---|---|
|生成する| .defaultCenter() | .default |
|通知する| postNotificationName("listDidLoad") | post(name: NSNotification.Name("listDidLoad") |

さて本題ですが、
今回は、NotificationCenterをプロトコルを利用して
実装したいと思います。

# 実装手順
## 1. プロトコルを定義する

### 1.1. 付属型でNotificationを定義する

```swift:Notifier.swift
protocol Notifier {
    associatedtype Notification: RawRepresentable
}
```

### 1.2. 通知用のプロトコルにNotificationCenter用のラッパーメソッドを拡張する
RawValueがStringのものだけを対象とします。

```swift:Notifier.swift
extension Notifier where Notification.RawValue == String {

    //RawValueをString型に変換する
    fileprivate static func nameFor(notification: Notification) -> String {
        return "\(notification.rawValue)"
    }
    // 登録用のラッパーメソッド
    static func addObserver(observer: AnyObject,
                            selector: Selector,
                            notification: Notification) {
        let name = nameFor(notification: notification)

        NotificationCenter.default.addObserver(observer,
                         selector: selector,
                         name: NSNotification.Name(rawValue: name),
                         object: nil)
    }

    // 通知用のラッパーメソッド
    static func postNotification(notification: Notification,
                                 object: AnyObject? = nil,
                                 userInfo: [String : Any]? = nil) {

        let name = nameFor(notification: notification)

        NotificationCenter.default.post(name: NSNotification.Name(rawValue: name),
                                        object: object,
                                        userInfo: userInfo)
    }

    // 削除用のラッパーメソッド
    static func removeObserver(observer: AnyObject,
                               notification: Notification,
                               object: AnyObject? = nil) {

        let name = nameFor(notification: notification)

        NotificationCenter.default.removeObserver(observer,
                            name: NSNotification.Name(rawValue: name),
                            object: object)
    }
}
```

# 2. イベントを定義する

## 2.1. イベントクラスにNotifierプロトコルを実装し、イベント名を定義する

```swift:Event.swift
final class Event: Notifier {

    enum Notification: String {
        case photoListDidLoad
        case photoDetailDidLoad
    }
}
```

# 3. 利用方法
ロードボタンを押下すると、通知を受信するサンプルです。
（同一画面内で登録→通知→通知受信→削除まで）

```swift:ViewController.swift

import UIKit

extension Selector {
    static let photoListDidLoad = #selector(ViewController.photoListDidLoad)
}

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        add()
    }

    //登録
    func add() {
        Event.addObserver(observer: self,
                            selector: .photoListDidLoad,
                            notification: .photoListDidLoad)
    }

    //通知を受け取る
    func photoListDidLoad(notification: Notification) {
        print(#function)

        Event.removeObserver(observer: self,
                               notification: .photoListDidLoad)
    }

    @IBAction func didLoadTap(_ sender: UIButton) {
        post()
    }

    //通知
    fileprivate func post() {
        Event.postNotification(notification: .photoListDidLoad)
    }
}
```

#まとめ
[参考サイト](https://medium.com/swift-programming/swift-nsnotificationcenter-protocol-c527e67d93a1#.7jjhggnf5)をベースにSwift3に置き換えてみました。
大変勉強になりました。

ソースコードは、[Github](https://github.com/stv-ekushida/ios-notification-center-demo)にアップしてあります。
よろしければ、ご一緒に御覧ください。


誤り等ございましたら、ご指摘頂けますと、幸いです。


スマートテック・ベンチャーズでは、未経験だけどiOSの開発をやりたい！という人を募集しています。
Advent Calendarのスマートテック・ベンチャーズページに会社およびWantedlyのURLをのせていますので、興味のある方は是非ご覧ください。
https://www.wantedly.com/companies/st-ventures/info

明日は、@soudapさんです。
お楽しみに！