Swiftで遊ぼう! on Hatena

あしたさぬきblogでやってた初心者オヤジのiOSプログラミング奮闘記がHatenaに来ました

Swiftで遊ぼう! - 715 - Notificationもう少し続けます。

昨日小さなNotificationデモを説明しましたが、スタンフォード大学のポール先生のNotification実装方法が違うんです。

ということで少しだけデモを拡張します。実はNotificationクラスのインスタンスを作ってaddObserverメソッドを使って実装する方法がまだあります。

AppDelegateクラスに次のNotification.Nameクラスのグローバル定数を作ります。

static let AnotherNotification = 
  Notification.Name("AnotherApplicationDidEnterBackground")

そしてこの名前でNotificationクラスのインスタンスを作ります。どこでコードを書くか?applicationDidEnterBacground()メソッド内に加えます。

let notification = Notification(
    name: AppDelegate.AnotherNotification, 
    object: nil, 
    userInfo: ["key" : "Thisi is another notification message"])

この時重要なのがuserInfoのようです。[ String : AnyObject ]でkye-Valueのテクニックを使って色々と拡張できそうですが、今のところ私には、これを上手く利用する能力がありません(^_^;)。取りあえずメッセージを保持させました。

そして、このNotificationインスタンスをpostします。

この「post」メソッドには次の3つの種類がありました。

func post(Notification)
//1. 別途に作られたNotificationを送信するメソッドです。

func post(name: NSNotification.Name, object: AnyObject?)
//2. これは名前とオブジェクトからNotificationを作って
//   送信するメソッドです。

func post(name: NSNotification.Name, 
          object: AnyObject?, 
          userInfo: [NSObject : AnyObject]? = [:])
//3. 上記と同様でNotificationを作って送信しますが、
//   userInfoという情報も送れます。

当然、Notificationインスタンスを別途に作っているので、(1)のメソッドを使います。

ns.post(notification)

ここまでがAppDelegateクラスに加えたコードです。そしてこのNotificationを受け取るクラスがViewControllerなのでNotificationCenterにObserverとして登録します。

この登録するためのメソッド「addObserver」にもいくつか種類があります。

昨日のデモで使ったメソッドは次のselectorを使用するパターンで2つ用意されています。パラメータとしてString型の「name」を受け取るメソッドです。これは従来のStringy-typed型のシステムNotificationを扱う時に使います。

func addObserver(observer: AnyObject, 
                 selector: Selector, 
                 name: String?, 
                 object: AnyObject?)

そしてSwift 3βで用意されているのが次のメソッドです。

func addObserver(observer: AnyObject, 
                 selector: Selector, 
                 name: Name, 
                 object: AnyObject?)

Notification.Name型の「name」を受け取るメソッドなので、今のところは混在できます。

しかし、スタンフォード大学のポール先生は、iOS9開発講義の中で、もう一つのメソッドを使って説明しています。

func addObserver(forName: NSNotification.Name?, 
                 object: AnyObject?, 
                 queue: OperationQueue?, 
                 using: (Notification) -> Void)

このメソッドが一番OOP向きのメソッドでないかと思います。どう考えればいいのか良くわかりませんが、スレッドも考慮されています。Notificationから情報を受け取ることができ、コードをブロック(クロージャ)で処理することができます。そして上記の2つのメソッドがVoidを返すのと異なり、「NSObjectProtocol」型を返すんです。

ということでViewControllerに次の宣言を加えます。

var observer: NSObjectProtocol? = nil

オプショナル型のobserverを宣言して、viewDidLoad()メソッド内で実装させます。

override func viewDidLoad() {
    super.viewDidLoad()

// カスタムNotificationをNotificationCenterに登録
// 昨日の記事と同じ
    NotificationCenter.default().addObserver(
       self, 
       selector: #selector(someAction), 
       name: AppDelegate.originalNotification, 
       object: nil)

// システムで用意されているNotificationは「String」型を引数として受け取れます。
// 昨日の記事と同じ
    NotificationCenter.default().addObserver(
        self, 
        selector: #selector(anotherAction), 
        name: "UIApplicationDidEnterBackgroundNotification", 
        object: nil)

// 今日付け加えたコード
    observer = 
        NotificationCenter.default().addObserver(
            forName: AppDelegate.AnotherNotification, 
            object: nil, 
            queue: OperationQueue.main(), 
            using: { notification in
            if let sample = 
            notification.userInfo?["key"] as? String {
               print(sample)
        }
    })
}

当然deinitメソッドも少し変更になります。

deinit {
    NotificationCenter.default().removeObserver(self)
    if let acitiveObserver = observer {
        NotificationCenter.default().removeObserver(acitiveObserver)
    }
}

これをランしてHomeに戻ると次のように表示されました。

This is original notification message.
Thisi is another original message
This is system notification message.

これで何となく基本的なNotificationの挙動が理解できました。

今日はこれだけ。