iOS NotificationCenter以更好的方式

应用程序开发中的常见模式是通知( NSNotificationNotificationCenter )。 通过通知,您可以将消息广播到多个侦听器。 在许多情况下这可能很有用。 一个常见的示例是,如果您有许多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中的对应函数命名两个名称,但是我通常使用相同的名称

希望您喜欢该解决方案。 让我知道您在评论中的想法。 这是否可以进一步改善?