Avoid Retain Cycles, NSNotificationCenter?

2019-06-21 13:32发布

问题:

Will this category method allow me to avoid additional retains on NSNotificationCenter observers?

#import "NSNotificationCenter+Util.h"

@implementation NSNotificationCenter (Util)

- (void)addWeakObserver:(nonnull NSObject*)observer selector:(nonnull SEL)aSelector name:(nullable NSString *)aName object:(nullable id)anObject {
    __weak NSObject *weakObserver = observer;
    [self addObserver:weakObserver selector:aSelector name:aName object:anObject];
}

@end

The goal is to have the object die without having to remove it.


Note: I'm trying to avoid this causing retain cycles:

Be sure to invoke removeObserver:name:object: before notificationObserver or any object specified in addObserver:selector:name:object: is deallocated.

回答1:

No — weakObserver will be weak, so will automatically nil if observer is deallocated, but if addObserver:... retains the observer then it retains the observer. There's no history in an object as to the ways that previous references have held it, it's the references themselves that control their own behaviour.

However, NSNotificationCenter doesn't retain its observers, and observers almost never retain the notification centre. There is no retain cycle. The text you've quoted more or less says this: that pointers stored within the notification centre will become dangling, i.e. it is not asserting ownership.

What you've done also won't make the references stored within the centre automatically nil.

As of iOS 9 and OS X v10.11, this behaviour is already fixed. A weak reference is used by the notification centre for all objects that can be referenced weakly.



回答2:

NSNotificationCenter doesn't retain observer, so you won't create a retain cycle just using addObserver:selector:name:object:. You don't need a wrapper method for that.

The reason for the warning about calling removeObserver:name:object: is because NSNotificationCenter didn't use zeroing weak references until OS X 10.11 (El Capitan) and iOS 9. In operating systems prior to these versions, if you fail to remove observer from the notification center when observer is deallocated, then the notification center will continue trying to send notifications to observer. This will generally cause a crash or worse.

If your deployment target is at least OS X 10.11 or iOS 9, then you don't have to worry about removing observer when it is deallocated.

Note that if you use -[NSNotificationCenter -addObserverForName:object:queue:usingBlock:], then I believe you do have to worry about avoiding a retain cycle caused by the block strongly retaining your observer.