Sponsor Link
NotificationCenter
iOS アプリを作っていると、NotificationCenter からの通知に対して何かを実行したいということがあります。
デバイスの向きが変更されたときに、画面レイアウトを変更する必要があるときは、NotificationCenter から通知を受ける必要があります。
直近のケースでは、iOS デバイスの電源状態の変更に応じて、スクリーンロックの ON/OFF を切り替える必要がありました。
iOS のデバイスの電源状態は、以下のプロパティを参照することで確認できます。
UIDevice.current.batteryState
Apple のドキュメントは、こちら。
説明した記事は、こちら。
[iOS] 電源/バッテリー状態 と 画面ロック
AddObserver で observe
プロパティを参照するとその時点での状態が取得できるのですが、変更されたことを検知するためには、NotificationCenter を使う必要があります。
変更された時に通知を受け取る1つの方法として、NotificationCenter の addObserver メソッドを使って、通知を受け取る方法があります。
この方法は、iOS 14 でも問題なく動きます。
NotificationCenter と新しいフレームワーク Combine を組み合わせることでも同様の機能を実現できます。
いわゆる Reactive っぽく実装する方法を説明します。
Combine で observe
Combine フレームワークと同時に、既存のフレームワークの多くに手が入れられ、Combine で使いやすくなっています。
NotificationCenter は、Combine 対応したフレームワークの代表と言えるかもしれません。
これまでの addObserver とは別に、Combine と組み合わせて使用するために、 NotificationCenter に publisher というメソッドが追加されました。
Apple のドキュメントは、こちら。
指定した通知 (Notification) が発生すると、送信してくれる publisher です。
self.cancellable = NotificationCenter.default
.publisher(for: UIDevice.batteryStateDidChangeNotification)
.sink(receiveValue: { _ in
self.adaptBatteryStateChange()
})
上記のコードは、UIDevice の batteryStateDidChangeNotification が発生すると、sink に指定されている closure が実行されます。
.sink の返り値である AnyCancellable は、ローカル変数に保持してはいけません。
この例では、クラスのインスタンスプロパティとして保持しています。
ローカル変数に保持してしまうとスコープから外れた時に破棄されてしまいます。(キャンセルされることになります)
まとめ:NotificationCenter と Combine を組み合わせて使う方法
- NotificationCenter.default.publisher で publisher を作成する
- publisher を subscribe (sink 等) して、イベントを受け取り処理する
- AnyCancellable は、クラスプロパティ等で保持していないと、メモリが破棄されたときにキャンセルされてしまうので、注意
Apple も同様の Article を出してます。
Swift 学習におすすめの本
詳解Swift
Swift の学習には、詳解 Swift という書籍が、おすすめです。
著者は、Swift の初期から書籍を出していますし、Swift の前に主力言語だった Objective-C という言語についても同様の書籍を出しています。
最新版を購入するのがおすすめです。
現時点では、上記の Swift 5 に対応した第5版が最新版です。
Swift ポケットリファレンス
Swift を学んでも、プログラミング言語の文法を全て記憶しておくことは無理なので、ちょっとした文法の確認をするために、リファレンス本を手元に置いておくと便利です。
Swift4 までしか対応していないので、理解して参照する必要があります。
Sponsor Link