[iOS 8] Swift で NSNotification の userInfo を扱う

Swift で NSNotification の userInfo を扱う

個人的にハマったので情報共有。

Swift で NSNotification の userInfo を使おうと思った場合、Objective-C ほど簡単には扱えません。
userInfo の型は次のようになっているので、Optional Value やら AnyObject やらで、アンラップしたりキャストしたりする必要があります。

class NSNotification : NSObject, NSCopying, NSCoding {
    // ...
    var userInfo: [NSObject : AnyObject]? { get }
    // ...
}

色々調べて試した結果、次の2通りのパターンのどちらかを使うのがいいのではないかと思いました。

  1. 変数宣言時にアンラップ & キャストする
  2. Value-Binding 時にアンラップ & キャストする

サンプルコード

1. 変数宣言時にアンラップ & キャストする

if let userInfo = notification.userInfo {
    let value = userInfo["number"]! as Int
    let plus10 = value + 10
    println(plus10)
}

2. Value-Binding 時にアンラップ & キャストする

if let userInfo = notification.userInfo as [String: Int]! {
    let value = userInfo["number"]!
    let plus10 = value + 10
    println(plus10)
}

私はアンラップが1回で済むので、前者のほうが好きです。
また、次のように短く書くこともできますが、userInfo が nil の場合にランタイムエラーとなるので、あまりオススメはしません。

let value = notification.userInfo!["number"]! as Int
let plus10 = value + 10
println(plus10)

フルサンプルコード

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let nc = NSNotificationCenter.defaultCenter()
        // 登録
        nc.addObserver(self, selector: "handleTestNotification:", name: "testNotification", object: nil)
        // 通知
        nc.postNotificationName("testNotification", object: nil, userInfo: ["number": 100])
    }

    func handleTestNotification(notification: NSNotification) {

        // 変数宣言時にアンラップ & キャストする方法
        if let userInfo = notification.userInfo {
            let value = userInfo["number"]! as Int
            let plus10 = value + 10
            println(plus10)
        }

        // Value-Binding 時にアンラップ & キャストする方法
        if let userInfo = notification.userInfo as [String: Int]! {
            let value = userInfo["number"]!
            let plus10 = value + 10
            println(plus10)
        }

        // 1行で書く方法。ただしuserInfoがnilの場合はランタイムエラー
        let value = notification.userInfo!["number"]! as Int
        let plus10 = value + 10
        println(plus10)
    }
}

まとめ

Swift は type safe な言語になっているため、Objective-C よりも細かく型を意識しなければなりません。
はじめは少し難しいですが、一つ一つ身につけていきましょう。