在很多文章裡面都介紹了RAC的用法,其中對於NSNotificationCenter的介紹實在太少了。只說用RAC來處理的話不用removeObserver,但是其實不然。
如果這個介面是被push過來的。 在viewDidLoad中,監聽通知,使用RAC。 然後pop回去,再push進來。。。 結果就是這個通知被新增了多個觀察者,而之前的已經被釋放了。看似沒問題,因為向nil發訊息是沒問題的,但是如果裡面還有單例的訪問,或是像上一篇文章說的,用->運算子的話,就會出現嚴重的問題。 就是說,viewDidLoad走幾次,下次通知觸發的時候就會走幾遍block。
因為RAC的監聽通知的實現原理是:
@implementation NSNotificationCenter (RACSupport)
- (RACSignal *)rac_addObserverForName:(NSString *)notificationName object:(id)object {
@unsafeify(object);
return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
@strongify(object);
id observer = [self addObserverForName:notificationName object:object queue:nil usingBlock:^(NSNotification *note) {
[subscriber sendNext:note];
}];
return [RACDisposable disposableWithBlock:^{
[self removeObserver:observer];
}];
}] setNameWithFormat:@"-rac_addObserverForName: %@ object: <%@: %p>", notificationName, [object class], object];
}
@end
複製程式碼
就是訂閱機制。subscribeNext就是訂閱。常理之中,如何移除訂閱呢?肯定是呼叫RACDisposable中的dispose方法。注意,[NSNotificationCenter defaultCenter] removeObserver是無效的。 因為我們訂閱的是RAC的signal。
但是在RAC的實現裡面,RACDisposable的確是建立了,卻沒有合適的時候呼叫dispose方法。所以下面的block根本就不會走,根本不會removeObserver!
[RACDisposable disposableWithBlock:^{
[self removeObserver:observer];
}];
複製程式碼
它return給誰了?另外NSNotificationCenter是個單例,所以它的rac_willDeallocSignal肯定是程式結束的時候才會有,並且它的實現裡面並沒有訂閱rac_willDeallocSignal。
我們想要移除這個觀察者只有一個辦法,就是把這個返回的RACSignal用RACDisposable來接收,在控制器的dealloc中,呼叫它的dispose方法。 但是這樣做,得不償失,這樣控制器就要持有這個返回的結果。倒不如用系統原來的做法了。
RAC固然還是相當強大的,但是在需要監聽通知的時候,不推薦使用RAC!
如果有什麼不同意見,歡迎在評論區留言討論~