NotificationCenter是一个非常实用的工具。但是用Foundation中的API来实现很冗长,完全是字符串和值的组合。每次需要通知时都使用这些值是非常尴尬的。
在Swift中使用泛型,我们可以使它变得更优雅,这样我们可以专注于使用强类型通知的内容。
通过CocoaPods安装
pod 'SweetNotifications'
UIKeyboard通知包含在子规范 SweetNotifications/UIKeyboard
中。通知类型有4种:
UIKeyboardWillShowNotification
UIKeyboardDidShowNotification
UIKeyboardWillHideNotification
UIKeyboardDidHideNotification
以 UIKeyboardWillShowNotification
为例,进行注册
listener = NotificationCenter.default.watch { (notification: UIKeyboardWillShowNotification) in
print(notification.frameBegin)
print(notification.frameEnd)
print(notification.animationDuration)
print(notification.animationOption)
print(notification.isCurrentApp)
}
别忘了稍后取消注册
NotificationCenter.default.removeObserver(listener)
注意:即将支持自注册
有一些通知不包含 userInfo
字典。在这种情况下,我们可以简单地监视命名事件
listener = NotificationCenter.default.watch(for: Notification.Name.UIApplicationWillTerminate) {
// save all the important things!
}
目前,还需要手动取消注册。
通过采用 SweetNotification
,您可以轻松创建自己的通知类型
struct ValueChangedNotification: SweetNotification {
let source: Source
init(userInfo: [AnyHashable: Any]) throws {
guard let sourceString = userInfo["source"] as? String else {
throw SerializationError.missingSource
}
switch userInfo["source"] as? String {
case "API"?:
source = .api
case "local"?:
source = .local
default:
throw SerializationError.unknownSource(userInfo["source"] as? String ?? "<Not a string>")
}
}
init(source: Source) {
self.source = source
}
func toUserInfo() -> [AnyHashable: Any]? {
switch source {
case .api:
return ["source": "API"]
case .local
return ["source": "local"]
}
}
enum Source {
case api, local
}
}
所有内容都是类型安全的 :)
let valueChangedNotification = ValueChangedNotification(source: .api)
NotificationCenter.default.post(valueChangedNotification)
测试自定义通知非常简单
func testInitWithUserInfo_sourceStringIsValid_sourceSetCorrectly() {
let expectedPairs: [String: ValueChangedNotification.Source] = ["API": .api, "local": .local]
for (sourceString, expectedSource) in expectedPairs {
let userInfo: [String: String] = ["source": sourceString]
do {
let notification = try ValueChangedNotification(userInfo: userInfo)
XCTAssertEqual(expectedSource, notification.source)
} catch {
XCTFail("Unexpected failure: \(error)")
}
}
}