iOS 自动释放的NSNotificationCenter
借鉴与 fbkvocontroller
自己实现一个自动释放的 NSNotificationCenter,
fbkvocontroller
是一个可以自动释放的kvo,并且提供了block 等方式。
具体实现如下:
@interface NSNotificationCenter(free)
- (void)pbtSafe_addObserver:(id)observer selector:(SEL)aSelector name:(NSNotificationName)aName object:(id)anObject;
@end
@interface PTVNotifitionToken : NSObject
@property (nonatomic, strong) NSString* token;
@property (nonatomic, strong) NSNotificationCenter *center;
@property (nonatomic, weak) id observe;
@end
@implementation PTVNotifitionToken
- (void)dealloc {
if (self.center && self.token) {
[self.center removeObserver:self.observe
name:self.token
object:nil];
}
}
@end
@implementation NSNotificationCenter(free)
- (void)pbtSafe_addObserver:(id)observer selector:(SEL)aSelector name:(NSNotificationName)aName object:(id)anObject {
PTVNotifitionToken *token = [PTVNotifitionToken new];
token.center = self;
token.token = aName;
token.observe = observer;
objc_setAssociatedObject(observer, aName.UTF8String, token, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[self addObserver:observer
selector:aSelector
name:aName object:anObject];
}
@end
原理非常简单,调用 pbtSafe_addObserver
的时候,动态的创建一个 PTVNotifitionToken,对象,通过关联 objc_setAssociatedObject ,给 observer,
我们知道,在自己的dealloc 函数调用之后会去释放和自己关联的obj,这样子就会调用 PTVNotifitionToken 的 dealloc 函数,然后调用 removeObserver
去释放。
方案②
static inline void BMP_EXChangeInstanceMethod(Class _originalClass ,SEL _originalSel,Class _targetClass ,SEL _targetSel){
Method methodOriginal = class_getInstanceMethod(_originalClass, _originalSel);
Method methodNew = class_getInstanceMethod(_targetClass, _targetSel);
method_exchangeImplementations(methodOriginal, methodNew);
}
BMP_EXChangeInstanceMethod([NSNotificationCenter class], @selector(addObserver:selector:name:object:), [NSNotificationCenter class], @selector(BMP_addObserver:selector:name:object:));
BMP_EXChangeInstanceMethod([UIViewController class], NSSelectorFromString(@"dealloc"), [self class], NSSelectorFromString(@"BMP_dealloc"));
@implementation NSNotificationCenter (NotificationProtector)
- (void)BMP_addObserver:(id)observer selector:(SEL)aSelector name:(NSNotificationName)aName object:(id)anObject{
objc_setAssociatedObject(observer, NSNotificationProtectorKey, NSNotificationProtectorValue, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[self BMP_addObserver:observer selector:aSelector name:aName object:anObject];
}
@end
@implementation UIViewController (NotificationProtector)
- (void)BMP_dealloc{
NSString *value = (NSString *)objc_getAssociatedObject(self, NSNotificationProtectorKey);
if ([value isEqualToString:NSNotificationProtectorValue]) {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
[self BMP_dealloc];
}
@end
阅读博客看到的,大致原理就是hook NSNotificationCenter 的方法,然后通过关联做一个标记,等到dealloc的时候判断一下是否有添加通知这样子!
END
考虑使用runtime 但是系统会调用很多次 addObserver 函数,会造成重复释放这种问题。