從 iOS 9 開始,即使不移除觀察者對(duì)象,程序也不會(huì)出現(xiàn)異常。
對(duì)于addObserver:要分ViewController和普通NSObject兩個(gè)說起
ViewController:在調(diào)用ViewController的dealloc的時(shí)候,系統(tǒng)會(huì)調(diào)用[[NSNotificationCenter defaultCenter]removeObserver:self]方法,所以如果是在viewDidLoad中使用addObserver添加監(jiān)聽者的話可以省掉移除。
普通NSObject:在iOS9之后,NSObject也會(huì)像ViewController一樣在dealloc時(shí)調(diào)用[[NSNotificationCenter
defaultCenter]removeObserver:self]方法,在iOS9之前的不會(huì)調(diào)用,需要自己寫。
但是在使用類別的時(shí)候如果我們添加了通知,那么我們是沒有辦法在類別里面重寫dealloc的,如果不移除通知就會(huì)出現(xiàn)野指針,這個(gè)時(shí)候我們就可以在iOS9以上使用addObserver,將通知的移除交給系統(tǒng),iOS9一下使用addObserverForName+weakSelf,雖然通知依然存在,但是不會(huì)調(diào)用doSomeThing方法(不要直接在block里面寫處理過程?。?。
為什么 iOS 9 之前需要手動(dòng)移除觀察者對(duì)象?
觀察者注冊(cè)時(shí),通知中心并不會(huì)對(duì)觀察者對(duì)象做 retain 操作,而是對(duì)觀察者對(duì)象進(jìn)行unsafe_unretained 引用。
什么是unsafe_unretained?因?yàn)?Cocoa 和 Cocoa Touch 中的一些類仍然還沒有支持 weak 引用。所以,當(dāng)我們想對(duì)這些類使用弱引用的時(shí)候,只能用unsafe_unretained來替代。
// for attribute
@property (unsafe_unretained) NSObject *unsafeProperty;
// for variables
NSObject *__unsafe_unretained unsafeReference;
不安全引用(unsafe reference)和弱引用 (weak reference) 類似,它并不會(huì)讓被引用的對(duì)象保持存活,但是和弱引用不同的是,當(dāng)被引用的對(duì)象釋放的時(shí),不安全引用并不會(huì)自動(dòng)被置為 nil,這就意味著它變成了野指針,而對(duì)野指針發(fā)送消息會(huì)導(dǎo)致程序崩潰。
因此,觀察者對(duì)象在釋放之前必須從通知中心移除引用,否則通知中心就會(huì)給野指針?biāo)玫膶?duì)象發(fā)送消息,導(dǎo)致程序崩潰。既然如此,為什么通知中心不對(duì)觀察者對(duì)象進(jìn)行弱引用呢?我們剛才已經(jīng)提到,Cocoa 和 Cocoa Touch 中的一些類還沒有支持弱引用,所以采用不安全的引用只是為了兼容舊的版本。
從 iOS 9 開始通知中心會(huì)對(duì)觀察者進(jìn)行弱引用,所以不需要在觀察者對(duì)象釋放之前從通知中心移除。但是,通過-[NSNotificationCenter addObserverForName:object:queue:usingBlock]方法注冊(cè)的觀察者依然需要手動(dòng)的釋放,因?yàn)橥ㄖ行膶?duì)它們持有的是強(qiáng)引用。