SafeKVO

防止多次addobser 和 多次 remove 导致的错误

赋值粘贴下面代码 放进项目即可

NSObject+SafeKVO.h

#import 

NS_ASSUME_NONNULL_BEGIN

@interface NSObject (SafeKVO)


/*!
 @method
 @abstract   移除所有观察的keypath
 */
- (void)removeAllObserverdKeyPath;

@end

NS_ASSUME_NONNULL_END

NSObject+SafeKVO.m


#import "NSObject+SafeKVO.h"
#import 
@implementation NSObject (SafeKVO)
 
+ (void)load {
    
    Method originAddM = class_getInstanceMethod([self class], @selector(addObserver:forKeyPath:options:context:));
    Method swizzAddM = class_getInstanceMethod([self class], @selector(swizz_addObserver:forKeyPath:options:context:));
    
    Method originRemoveM = class_getInstanceMethod([self class], @selector(removeObserver:forKeyPath:context:));
    Method swizzRemoveM = class_getInstanceMethod([self class], @selector(swizz_removeObserver:forKeyPath:context:));
    
    IMP originAddMIMP = class_getMethodImplementation([self class], @selector(addObserver:forKeyPath:options:context:));
    IMP originRemoveIMP = class_getMethodImplementation([self class], @selector(removeObserver:name:object:));
    
    BOOL hasAddM = class_addMethod([self class], @selector(addObserver:forKeyPath:options:context:), originAddMIMP, method_getTypeEncoding(originAddM));
    
    
    BOOL hasRemoveM = class_addMethod([self class], @selector(removeObserver:forKeyPath:context:), originRemoveIMP, method_getTypeEncoding(originRemoveM));
    
    // excute once
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (!hasAddM) {
            method_exchangeImplementations(originAddM, swizzAddM);
        }
        if (!hasRemoveM) {
            method_exchangeImplementations(originRemoveM, swizzRemoveM);
        }
    });
}
 
- (void)swizz_addObserver:(nonnull NSObject *)observer forKeyPath:(nonnull NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context {
    if (![self hasKey:keyPath]) {
        // 调用系统的添加observer 方法
        [self swizz_addObserver:observer forKeyPath:keyPath options:options context:context];
    }
}
- (void)swizz_removeObserver:(nonnull NSObject *)observer forKeyPath:(nonnull NSString *)keyPath context:(nullable void *)context {
    if ([self hasKey:keyPath]) {
        [self swizz_removeObserver:observer forKeyPath:keyPath context:context];
    }
}
 
- (void)removeAllObserverdKeyPath {
    id info = self.observationInfo;
    NSArray *arr = [info valueForKeyPath:@"_observances._property._keyPath"];
    for (NSString *keyPath in arr) {
        // TODO context 需要考虑值不为nil的时候
        [self removeObserver:self forKeyPath:keyPath context:nil];
    }
}
 
- (BOOL)hasKey:(NSString *)kvoKey {
    BOOL hasKey = NO;
    id info = self.observationInfo;
    NSArray *arr = [info valueForKeyPath:@"_observances._property._keyPath"];
    for (id keypath in arr) {
        // 存在kvo 的key
        if ([keypath isEqualToString:kvoKey]) {
            hasKey = YES;
            break;
        }
    }
    return hasKey;
}
 
@end

你可能感兴趣的:(SafeKVO)