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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM