iOS NotificationCenter以更好的方式
应用程序开发中的常见模式是通知( NSNotification和NotificationCenter )。 通过通知,您可以将消息广播到多个侦听器。 在许多情况下这可能很有用。 一个常见的示例是,如果您有许多UIViewControllers都需要在模型更改时进行更新。
但是,我觉得使用NotificationCenter的标准方法是容易出错,复杂且冗长。 我主要使用另一种方法,您可以在其中创建自己的NotificationCenter版本。
首先,以NotificationCenter的正常使用为例:
扩展Notification.Name {
静态让didUpdateCar = Notification.Name(“ didUpdateCar”)
静态让didReceiveData = Notification.Name(“ didReceiveData”)
}
类MyViewController:UIViewController {
覆盖func viewDidLoad(_动画:布尔){
super.viewDidLoad(动画)
setupNotifications()
}
私人功能setupNotifications(){
NotificationCenter.default.addObserver(自身,选择器:#selector(didUpdateCar(_ :)),名称:.didUpdateCar,对象:无)
NotificationCenter.default.addObserver(自己,选择器:#selector(didReceiveData(_ :)),名称:.didReceiveData,对象:无)
// ...一长串清单
}
deinit {
NotificationCEnter.default.removeObserver(自己)
}
@objc私人函数didReceiveData(_通知:NSNotification){
//如果您在发送方更改了userInfo,则此操作无提示。 崩溃喜欢?
如果让数据= notification.userInfo为? [String:Int] {
用于数据{中的(name,ageInYears)
print(“ \(名称)是\(ageInYears)岁。”)
}
}
}
}
类AnotherViewController:UIViewController {
func didClickButton(){
//让我们祈祷接收者知道我们要发送的内容
let data = [“ Jonas”:20,“ Andrea”:3,“ Oscar”:42]
NotificationCenter.default.postNotification(名称:.didReceiveData,对象:数据)
}
}
在这里,我们只使用标准的API。 我们在Notification.Name中添加了扩展名,以使设置更加流畅。 除此之外,这是广播通知的默认方式。 我不喜欢这种方法:
- 我们使用字符串文字。 感觉很旧,不好并且容易出错。
- 我们强制转换userInfo 。 接收者需要知道有效载荷的类型。 如果我们需要发送更多的参数,则需要将更多的强制转换或字符串常量作为键。
- addObserver函数相当长,需要为每个侦听器重复。
- 我们必须为字符串文字,通知名称变量和回调方法提供名称。
导入UIKit
@objc协议NotificationDelegate:AnyObject {
@objc可选func didUpdateCar()
@objc可选func didReceiveData(_ data:[String:Int])
// ...
} //与您的其他经理一起放置
让NotificationManager = NotificationManager()类NotificationManager {
私人var代表= [Weak ]()
func addDelegate(_代表:NotificationDelegate){
Representatives.append(弱(值:委托))
}
func removeDelegate(_代表:NotificationDelegate){
如果让indexToRemove =委托人。索引(其中:{$ 0.value ===委托人))
Representatives.remove(at:indexToRemove)
}
}
func didUpdateCar(){
Representatives.forEach {$ 0.value?.didUpdateCar?()}
}
func didReceiveData(_ data:[String:Int]){
Representatives.forEach {$ 0.value?.didReceiveData?(data)}
}
}
解决方案非常简单。 我们在协议中为每种通知类型创建一个可选的func。 我们还创建了一个广播给所有代表的功能。
然后,NotificationManager会存储在您喜欢的任何位置。 如果您希望将其作为单例,则可以完成,但是我更喜欢将其作为实例放置在某个地方。
在Weak.swift中,我们为弱引用定义了一个容器。 这是必需的,因为普通数组对其元素有很强的引用。
类Weak {
弱var值:T?
初始化(值:T){
self.value =值
}
}
这是使用NotificationManager的方法:
类ExampleViewController:UIViewController {
覆盖func viewDidLoad(){
super.viewDidLoad()
notificationManager.addDelegate(个体)
}
deinit {
notificationManager.removeDelegate(个体)
}
}
扩展ExampleViewController:NotificationDelegate {
func didReceiveData(_ data:[String:Int]){
用于数据{中的(name,ageInYears)
print(“ \(名称)是\(ageInYears)岁。”)
}
}
}
如您所见,设置变得更加简洁,一行用于添加self作为代理,另一行用于删除。 然后,扩展您的类并实现要侦听的NotificationDelegate协议的可选功能。 这意味着,即使您听了多个通知,您仍然只需要addDelegate一线式设置即可!
广播也变得很干净:
类AnotherViewController:UIViewController {
func didClickButton(){
let data = [“ Jonas”:20,“ Andrea”:3,“ Oscar”:“ 42”]
notificationManager.didReceiveData(数据)
}
}
您可以在此处以任何所需的方式设置参数,而无需从userInfo进行任何强制转换。
总结一下:
- 没有更多的字符串文字
- 不再需要强制转换,我们可以传递多个类型化的参数
- addDelegate函数非常短,每个类仅需要一次
- 我们仍然需要为回调函数和NotificationManager中的对应函数命名两个名称,但是我通常使用相同的名称
希望您喜欢该解决方案。 让我知道您在评论中的想法。 这是否可以进一步改善?