扩展通知中心

Extending NotificationCenter

我正在尝试为 NotificationCenter

编写扩展

我发现语法有点多 "boilerplatey",我想提供一个简单的扩展来简化发布和观察。

我可以像这样发送一个事件

NotificationCenter.dispatch(key: <#T##String#>, payload: <#T##[String : String]#>)

不过我想以类似的方式观察事件。

我正在尝试创建类似

的内容
NotificationCenter.observe(key: <#T##String#>, handler: <#T##() -> Void#>)

然而这是不正确的。我不确定如何处理传递应该在观察时触发的选择器函数?

这是我目前的尝试。

extension NotificationCenter {
    static func dispatch(key: String, payload: [String: String] = [:]) {
        NotificationCenter.default.post(name: NSNotification.Name(rawValue: key), object: nil, userInfo: payload)
    }
    static func observe(key: String, handler: ()->Void) {
        NotificationCenter.default.addObserver(
            self, selector: handler, name: NSNotification.Name(rawValue: key), object: nil
        )
    }
}

你可以这样使用:

extension NotificationCenter {

    class func observe(name: NSNotification.Name, handler: @escaping (Notification) -> Void) {
        self.default.addObserver(forName: name, object: nil, queue: .main, using: handler)
    }

}

那么你可以这样使用它:

NotificationCenter.observe(name: UIResponder.keyboardDidShowNotification) { notification in
    // do something
}

尽管如此,您绝对应该查看 https://developer.apple.com/documentation/foundation/notificationcenter/1411723-addobserver 关于注销观察的内容。

听起来你需要这样的东西

extension NotificationCenter {
    static func dispatch(key: String, payload: [String: String] = [:]) {
        self.default.post(name: NSNotification.Name(rawValue: key), object: nil, userInfo: payload)
    }
    static func observe(key: String, handler: @escaping (Notification) -> Void) {
        self.default.addObserver(forName: NSNotification.Name(rawValue: key), object: nil, queue: .main, using: handler)
    }
}

NotificationCenter - 一个有用但看起来笨重的界面,感觉代码有点臃肿,因为有人来自 UNIX-like 线程同步语义......所以,这些扩展基于 S.O . & the 'Net, with a couple twists.

extension Notification.Name {
    static let patientlyWaiting = Notification.Name("patientlyWaiting")
    // .
    // . list your arbitrary waiter names here...
    // .
}
extension NotificationCenter {
    static func wait(_ name : Notification.Name) async {
        for await _ in NotificationCenter.default.notifications(named: name) {
            break;
        }
    }
    static func post(_ name : Notification.Name) {
        NotificationCenter.default.post(name: name, object: nil)
    }
    static func postProcessing(_ name: Notification.Name, using block: @escaping (Notification) -> Void)  {
        NotificationCenter.default.addObserver(forName: name, object: nil, queue: OperationQueue.main, using: block)
    }
}

要使用它,像这样:

等待通知:

@IBAction func doSomethingAsychronouslyButtonPushed(_ sender: Any)  {
    doSomethingAsynchronously()
    NotificationCenter.postProcessing(.patientlyWaiting, using: { _ in
        print("doSomethingAsynchronouslyButton completion handler called")
    })
}

通知中:

func doSomethingAsynchronously() {
     for n in ["Time", " ",  "consuming", " - ", "whatever"] {
          print("\(n)", terminator: "")
     }
     print("\n")
     NotificationCenter.post(.patientlyWaiting) 
}

注意:您可以避免使用闭包并使用 Swift 语言的 recently-added async/[=14= 进行内联等待] 支持(参见'wait()function in the extensions shown above), but I didn't provide an example of using that because I haven't been able to invokeasyncfunctions from selectors, such as from aUIButtonpress, directly or indirectly; because, any function that usesawaitneeds to be declaredasync. Specifically, #selector(afunc(_:)) doesn't match functions declared async, and I'm unaware of a function signature syntax that accounts for an asyncin function declaration (to pass to #选择器()`)。如果有人知道,请在评论中告诉我,我会更新答案。