iOS 自动释放的NSNotificationCenter

2018-01-15  本文已影响128人  杨柳小易

iOS 自动释放的NSNotificationCenter

借鉴与 <code>fbkvocontroller</code>自己实现一个自动释放的 NSNotificationCenter,

<code>fbkvocontroller</code> 是一个可以自动释放的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


原理非常简单,调用<code> pbtSafe_addObserver </code>的时候,动态的创建一个 PTVNotifitionToken,对象,通过关联 objc_setAssociatedObject ,给 observer,

我们知道,在自己的dealloc 函数调用之后会去释放和自己关联的obj,这样子就会调用 PTVNotifitionToken 的 dealloc 函数,然后调用 <code> removeObserver </code> 去释放。

方案②

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 函数,会造成重复释放这种问题。

上一篇下一篇

猜你喜欢

热点阅读