はじめに
NotificationCenter
を使ってクラス間で通知処理を行おうとしたらうまくいかなかったのでそのメモを残します。コピペで動くようにしてあるので、Playgroundなどで貼り付けて確認できます。
うまくいかない場合
先にうまくいかない場合を紹介。ざっくり説明すると、Sender
クラスはインスタンス化された時、test
という通知キーワードをpostします。
Receiver
クラスはインスタンス化された時、test
という通知キーワードを受け取れるようにし、受け取ったらtest()
を実行します。
import Foundation
class Sender {
let notificationCenter = NotificationCenter()
init() {
notificationCenter.post(name: NSNotification.Name(rawValue: "test"),
object: nil)
}
}
class Receiver {
let notificationCenter = NotificationCenter()
init() {
notificationCenter.addObserver(forName: .init(rawValue: "test"),
object: nil,
queue: nil,
using: { [unowned self] notification in
test()
})
}
func test() {
print("通知")
}
}
let receiver = Receiver()
let sender = Sender()
うまくいく場合
うまくいく場合を紹介します。うまくいかなかった場合との違いはNotificationCenter
をインスタンス化したものを利用しているのかということです。
notificationCenter
→NotificationCenter.default
import Foundation
class Sender {
init() {
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "test"),
object: nil)
}
}
class Receiver {
init() {
NotificationCenter.default.addObserver(forName: .init(rawValue: "test"),
object: nil,
queue: nil,
using: { [unowned self] notification in
test()
})
}
func test() {
print("通知")
}
}
let receiver = Receiver()
let sender = Sender()
原因
クラスでそれぞれNotificationCenter
をインスタンス化して使っているのが原因でした。クラス間をまたいで使っていないのでできないことは当たり前といえば当たり前ですが。
おまけ
それでもインスタンス化したものを使いたい!という場合の対処法について記述します。レアケースかもしれませんが、AVAudioPlayer
などでもこの考え方は活きるかと思います。もしかしたらこっちの方が一般的かも。
import Foundation
class Sender {
let notificationCenter = NotificationCenter()
func send() {
notificationCenter.post(name: NSNotification.Name(rawValue: "test"),
object: nil)
}
}
class Receiver {
let notificationCenter: NotificationCenter
init(initNC : NotificationCenter) {
self.notificationCenter = initNC
notificationCenter.addObserver(forName: .init(rawValue: "test"),
object: nil,
queue: nil,
using: { [unowned self] notification in
test()
})
}
func test() {
print("通知")
}
}
let sender = Sender()
let receiver = Receiver(initNC: sender.notificationCenter)
sender.send()//通知
先ほどのうまくいかなかった場合のソースコードの一部を以下のように変更しました。
-
Sender
クラスの通知を送る処理をinit()
ではなくsend()
で送るようにした。 -
Receiver
クラスにNotificationCenter
型の変数を定義した。
このようにすることでクラス間で共通のNotificationCenter
型の変数を使えるようになりました。