Help us understand the problem. What is going on with this article?

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

はじめに

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()
        }
    }
}
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした