关于 Notification 的使用
0x00 前言
一直以来,对于 Notification
的使用都理解得不是特别透彻,dealloc
中要不要移除 observer
,block
中要不要加 weak
,一直都是能加就加,根本未考虑过为什么要加或者说为什么可以不加。这篇记录就将这些问题一次性地弄个明白。
0x01 removeObserver?
Apple 的官方文档说明中,在 iOS 9.0,macOS 10.11 及以后的系统版本中,使用 addObserver:selector:name:object:
方式添加的通知可以不再手动移除通知。而使用 addObserverForName:object:queue:usingBlock:
方式添加的通知在之前是需要手动移除的,而在新版本中则没有特意指明是否需要移除。
那么我们就用代码来实际测试一下。
首先,我们为 NotificationCenter
添加一个扩展方法,用自定义的方法对 removeObserver
进行交换,并在自定义方法中输出我们想要的信息。这样就能够在退出界面时在控制台方便地看到 Notification
到底有没有移除 observer
。
1 | extension NotificationCenter { |
接下来我们创建三个界面,分别为 FirstController
、SecondController
和 ThirdController
。
在 FirstController
的 viewDidLoad
方法中调用 NotificationCenter.swizzling()
。
在 SecondController
中添加接收通知的代码:
1 | NotificationCenter.default.addObserver(self, selector: #selector(notificationReceived), name: .init("TestNotification"), object: nil) |
然后在 ThirdController
的 viewDidLoad
方法中发送通知:
1 | NotificationCenter.default.post(name: .init(rawValue: "TestNotification"), object: nil) |
此时便已万事俱备了,接下来开始我们的测试。
运行我们的 demo app,首先进入 FirstController
,然后 present 出 SecondController
,在第二个界面再次 present 出 ThirdController
。
此时, ThirdController
中的通知消息已经发出,控制台也能看到输出了 “Has received notifciation by selector.”,此时将 ThirdController
关闭,控制台再次打印出 “Observer has been removed”。这说明 ThirdController
关闭的时候自动调用了 removeObserver
方法。
再将 SecondController
关闭,控制台同样打印出 “Observer has been removed”,这说明的确不用再手动移除通知的 observer
了。
0x02 通知的 block 形式与 weak
将 SecondController
中的接收通知代码替换为 block 形式:
1 | NotificationCenter.default.addObserver(forName: .init("TestNotification"), object: nil, queue: .main) { (noti) in |
再以相同的流程跑一遍,可以发现关闭 SecondController
并没有打印 “Observer has been removed”,是因为 block
形式的通知不支持自动移除吗?我们在 deinit
中手动移除一下再来看看。
1 | deinit { |
再试一下,可以发现 deinit
方法根本没有调用,所以,根本原因其实是产生了循环引用导致不能正常释放。因此在 block
中添加weak,修改后的代码为:
1 | NotificationCenter.default.addObserver(forName: .init("TestNotification"), object: nil, queue: .main) { [weak self] (noti) in |
再运行一遍我们的demo,可以看到控制台输出了 “Observer has been removed” 和 “Second view controller deinited.” 这两句话,证明了 observer
已正常移除,SecondController
也已正常释放。
0x03 总结
通过以上的测试,可以得出结论,在iOS 9.0,macOS 10.11 及以后的版本中,NotificationCenter
的 observer
不再需要手动移除,使用 block
形式的通知时,需要加上 weak
以避免循环引用的出现。