LoginSignup
6
3

More than 5 years have passed since last update.

RxSwiftとenumでNSNotificationCenterを使いやすくした

Last updated at Posted at 2017-01-17

環境

Swift 2.3, Xcode 8.2

ふつうにNSNotificationCenterを使うと

こんなかんじになる。

// 通知
NSNotificationCenter.defaultCenter().postNotificationName("NotifName", object: nil)

// 購読
NSNotificationCenter.defaultCenter().addObserver(
    self,
    selector: #selector(MyViewController.onRecievedNotif),
    name: "NotifName",
    object: nil
)

// 購読解除
NSNotificationCenter.defaultCenter().removeObserver(self)

// 通知を受けたときの処理
func onRecievedNotif() {
    // do something
}

不満

  • 購読解除を忘れそう
  • コードが長い
  • notificationNameのタイポがこわい

RxSwiftを使ってシンプルに書けるようにした

private let bag = DisposeBag()
// 通知
NSNotifConstants.webViewClosed.post()

// 購読 & 通知を受けたときの処理 & 自身が破棄されたときに購読解除
NSNotifConstants.webViewClosed.asObservable()
    .subscribeNext { [unowned self] notif in
        // do something
    }
    .addDisposableTo(self.bag)

実装

RxCocoa による NSNotificationCenterの拡張メソッドrx_notificationを使用する。

NSNotifConstants.swift

import Foundation
import RxSwift
// NSNotificationCenterに使う
enum NSNotifConstants {

    // メインのタブを変更した
    case mainTab
    // アプリがバックグラウンドからフォアグラウンドに復帰した
    case appDidBecomeActive
    // お知らせ一覧を取得した
    case latestNotificationAtUpdated
    // お知らせ一覧を確認した
    case notificationsChecked
    // 自分のプロフィールが更新された
    case myProfileUpdated
    // WebViewが閉じた
    case webViewClosed

    var name: String {
        // 他のライブラリ等とnotificationの名前がかぶるのを防ぐためにprefixをつける
        return "myapp" + String(self.hashValue)
    }

    // 通知を送る
    func post(object: AnyObject? = nil, userInfo: [NSObject: AnyObject]? = nil) {
        NSNotificationCenter.defaultCenter().postNotificationName(
            self.name,
            object: object,
            userInfo: userInfo
        )
    }

    // 通知を購読する
    func asObservable() -> Observable<NSNotification> {
        return NSNotificationCenter.defaultCenter()
            .rx_notification(self.name)
            .observeOn(MainScheduler.instance)
    }
}

オブジェクトを送る場合

ときには通知と一緒にobjectを送りたい。
あまり綺麗ではないかもしれないが、こう書くことにした

// 通知
NSNotifConstants.myProfileUpdated.post(
    NSNotificationData.MyProfileUpdated(
        oldProfileData: oldData,
        newProfileData: newModel.toData()
    )
)

// プロフィールの変更を監視
NSNotifConstants.myProfileUpdated.asObservable()
    .map { $0.object as! NSNotificationData.MyProfileUpdated }
    .subscribeNext( [unowned self] profiles in
        // do something
    )
    .addDisposableTo(self.bag)

実装

NSNotifData

// NSNotificationCenterに使う
// objectに指定するためにNSObjectを継承する
final class NSNotifData: NSObject {

    final class MyProfileUpdated {
        // 自分のプロフィールが更新された
        let oldProfileData: MyProfileData?
        let newProfileData: MyProfileData
        init(oldProfileData: MyProfileData?, newProfileData: MyProfileData) {
            self.oldProfileData = oldProfileData
            self.newProfileData = newProfileData
        }
    }

}

さいごに

もっといい感じの実装があれば教えてください:)

6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3