はじめに
NotificationCenterでの複数の通知を待ちたいユースケースの実装例です。
複数の通知を待ち合わせ、すべての通知を受信した場合にコールバックを実行します。
使用例
NotificationWaiter.wait(for .someNotification) {
// .someNotificationの通知を受信した時
}
NotificationWaiter.wait(for [.fooNotification, .barNotification]) {
// .fooNotification, .barNotificationの通知をすべて受信した時
}
サンプルコード
/// NotificationCenterでの通知を1度だけコールバックで待つためのクラス
public enum NotificationWaiter {
/// 引数で指定したNotification.Nameが通知されるまで待ち、通知されたタイミングでcompletionを実行する
///
/// - Parameters:
/// - name: 対象となる通知名
/// - notificationCenter: 通知センター
/// - completion: 通知を受信した際に実行するクロージャー
static func wait(for name: Notification.Name,
notificationCenter: NotificationCenter = NotificationCenter.default,
completion: @escaping () -> Void) {
var token: NSObjectProtocol?
token = notificationCenter.addObserver(forName: name,
object: nil,
queue: nil) { _ in
guard let token = token else { return }
notificationCenter.removeObserver(token)
completion()
}
}
/// 引数で指定したNotification.Nameが全て通知されるまで待ち、全て通知されたタイミングでcompletionを実行する
///
/// - Parameters:
/// - names: 対象となる通知名の配列
/// - notificationCenter: 通知センター
/// - completion: 全ての通知を受信した際に実行するクロージャー
static func wait(for names: [Notification.Name],
notificationCenter: NotificationCenter = NotificationCenter.default,
completion: @escaping () -> Void) {
let dispatchGroup = DispatchGroup()
let dispatchQueue = DispatchQueue(label: "", attributes: .concurrent)
names.forEach { name in
dispatchGroup.enter()
dispatchQueue.async(group: dispatchGroup) {
wait(for: name) {
dispatchGroup.leave()
}
}
}
dispatchGroup.notify(queue: .main) {
completion()
}
}
}