NotificationCenterのaddObserverやCombineのsinkは同期実行である
環境
- Xcode: 15.1
調べたこと
NotificationCenter
のaddObserver
における処理や,Combine(Publisher
)のsink
における処理は非同期だと勝手に思っていたのですが(恥),
デバッグ実行していて「もしや同期実行なのでは・・・?」と不安になったのでPlaygroundで試してみました.(その通り同期実行でした.)
また,オブザーバ(サブスクライバ)の実行スレッドがどうなるのかも併せて確認しました.
NotificationCenter
以下のようなコードで試してみました.
import Foundation
func log(_ line: String) {
print("\(Date()) \(line)")
}
extension Notification.Name {
static let sampleNotification = Notification.Name("sampleNotification")
}
NotificationCenter.default.addObserver(forName: .sampleNotification, object: nil, queue: .none) { notification in
Thread.sleep(forTimeInterval: 2.0)
log("observer (queue=none): \(Thread.current.description)")
}
NotificationCenter.default.addObserver(forName: .sampleNotification, object: nil, queue: .main) { notification in
Thread.sleep(forTimeInterval: 2.0)
log("observer (queue=main): \(Thread.current.description)")
}
Task {
log("before post notification: \(Thread.current.description)")
NotificationCenter.default.post(name: .sampleNotification, object: nil)
log("after post notification: \(Thread.current.description)")
}
2024-03-16 10:22:53 +0000 before post notification: <NSThread: 0x60000171c140>{number = 4, name = (null)}
2024-03-16 10:22:55 +0000 observer (queue=none): <NSThread: 0x60000171c140>{number = 4, name = (null)}
2024-03-16 10:22:57 +0000 observer (queue=main): <_NSMainThread: 0x60000170c000>{number = 1, name = main}
2024-03-16 10:22:57 +0000 after post notification: <NSThread: 0x60000171c140>{number = 4, name = (null)}
はい,完全に同期実行でした.
スレッドは.none
(もしくはnil
)を指定した場合はpostしたスレッドと同じスレッドで,.main
を指定した場合はメインスレッドで実行されますが,いずれも同期実行です.
Combine
以下のようなコードで試してみました.
import Foundation
import Combine
func log(_ line: String) {
print("\(Date()) \(line)")
}
let subject = PassthroughSubject<Int, Never>()
subject.sink { value in
Thread.sleep(forTimeInterval: 2.0)
log("received: \(value) \(Thread.current.description)")
}
Task {
log("before send: \(Thread.current.description)")
subject.send(42)
log("after send: \(Thread.current.description)")
}
2024-03-16 10:33:34 +0000 before send: <NSThread: 0x60000170c340>{number = 6, name = (null)}
2024-03-16 10:33:36 +0000 received: 42 <NSThread: 0x60000170c340>{number = 6, name = (null)}
2024-03-16 10:33:36 +0000 after send: <NSThread: 0x60000170c340>{number = 6, name = (null)}
はい,こちらも完全に同期実行でした.
スレッドはsend
したスレッドと同じスレッドでした.
一般的にPub/Subという名前からは非同期実行をイメージしてしまうかもしれないので,要注意ですね.