Last active
December 5, 2022 15:15
-
-
Save fxm90/68e2cc3cd6b63751c225b1e1249088cc to your computer and use it in GitHub Desktop.
Extension for "NotificationCenter" to observe a notification just once and directly unsubscribe.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// NotificationCenter+ObserveOnce.swift | |
// | |
// Created by Felix Mau on 18.10.20. | |
// Copyright © 2020 Felix Mau. All rights reserved. | |
// | |
import UIKit | |
extension NotificationCenter { | |
/// Adds an observer to the given notification center, which fires just once. | |
/// | |
/// Note: | |
/// - Same parameters as "addObserver", but with default properties | |
/// See http://apple.co/2zZIYJB for details. | |
/// | |
/// Parameters: | |
/// - name: The name of the notification for which to register the observer | |
/// - object: The object whose notifications the observer wants to receive | |
/// - queue: The operation queue to which block should be added. | |
/// - block: The block to be executed when the notification is received. | |
func observeOnce(forName name: NSNotification.Name?, | |
object obj: Any? = nil, | |
queue: OperationQueue? = nil, | |
using block: @escaping (Notification) -> Swift.Void) { | |
var observer: NSObjectProtocol? | |
observer = addObserver(forName: name, | |
object: obj, | |
queue: queue) { [weak self] notification in | |
// Here we directly remove the observer, so this closure will be executed just once. | |
self?.removeObserver(observer!) | |
block(notification) | |
} | |
} | |
} |
When targeting iOS versions >= 13 you can simplify the code by using the combine operator first()
:
NotificationCenter.default
.publisher(for: Notification.Name)
.first()
.sink { notification in
// ...
}
In addition to @fxm90 answer, To avoid the sink()
warning (Result of call to 'sink(receiveValue:)' is unused
), You can use:
import Foundation
import Combine
// Source + TestCase: https://gist.github.com/fxm90/68e2cc3cd6b63751c225b1e1249088cc
extension NotificationCenter {
/// Adds an observer to the given notification center, which fires just once.
///
/// Note:
/// - Same parameters as "addObserver", but with default properties
/// See http://apple.co/2zZIYJB for details.
///
/// Parameters:
/// - name: The name of the notification for which to register the observer
/// - queue: The operation queue to which block should be added.
/// - block: The block to be executed when the notification is received.
func observeOnce(forName name: NSNotification.Name,
queue: OperationQueue? = nil,
using block: @escaping (Notification) -> Swift.Void) {
var cancellable: AnyCancellable?
cancellable = NotificationCenter.default
.publisher(for: name)
.receive(on: queue ?? OperationQueue.main)
.first()
.sink {
block($0)
cancellable?.cancel()
}
}
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Testcase