iOS 自动移除KVO观察者

对NSObject写一个分类:

 

#import <Foundation/Foundation.h>

@interface NSObject (FMObserverHelper)

- (void)fm_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;

@end

 

 

//  对象被释放之前, 会调用dealloc方法, 其持有的实例变量也会被释放.

//  在监听注册时, 为self和Observer关联个临时对象, 当两者在释放实例变量时, 借助这个时机, 在临时对象的dealloc方法中, 移除Observer

//  self在被释放之前, 会先释放其持有的关联属性, self并未完全释放, 可在临时对象中target却成了nil.

//  weak: 持有者不会对目标进行retain, 当目标销毁时, 持有者的实例变量会被置空

//  unsafe_unretained: 持有者不会对目标进行retain, 当目标释放后, 持有者的实例变量还会依然指向之前的内存空间(野指针)

//  如果Observer提前释放,而添加关联属性, 两者还不能同时持有临时对象, 否则临时对象也不会及时的释放,既然一个不行, 那就各自关联一个.

//  两个关联属性释放的同时, 进行了两次观察移除的操作. 为避免这个问题, 需要判断weak引用的实例变量factor是否为空即可

 

#import "NSObject+FMObserverHelper.h"

#import <objc/runtime.h>

 

@interface FMObserverHelper : NSObject

 

@property (nonatomic, unsafe_unretained) id target;

@property (nonatomic, unsafe_unretained) id observer;

@property (nonatomic, strong) NSString * keyPath;

@property (nonatomic, weak) FMObserverHelper * factor;

 

@end

 

@implementation FMObserverHelper

 

- (void)dealloc {

    if ( _factor ) {

        [_target removeObserver:_observer forKeyPath:_keyPath];

    }

}

@end

 

@implementation NSObject (FMObserverHelper)

 

- (void)fm_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath {

    [self addObserver:observer forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:nil];

    

    FMObserverHelper * helper = [FMObserverHelper new];

    FMObserverHelper * sub = [FMObserverHelper new];

    

    sub.target = helper.target = self;

    sub.observer = helper.observer = observer;

    sub.keyPath = helper.keyPath = keyPath;

    helper.factor = sub;

    sub.factor = helper;

    

    const char * helpeKey = [NSString stringWithFormat:@"%zd", [observer hash]].UTF8String;

    objc_setAssociatedObject(self, helpeKey, helper, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

    objc_setAssociatedObject(observer, helpeKey, sub, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

}

 

@end

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值