LoginSignup
6
2

More than 5 years have passed since last update.

NotificationCenterでの複数の通知をコールバックで待ちあわせる

Posted at

はじめに

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()
        }
    }
}
6
2
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
2