美文网首页iOS开发
iOS 反 KVO(如何知道属性被监听了)

iOS 反 KVO(如何知道属性被监听了)

作者: chenyu1520 | 来源:发表于2018-01-30 18:29 被阅读1050次

    在 iOS 开发中监听一个对象的某个属性,很容易做到,然后有时候我们在写一些安全性的代码或者框架时,不想让别人监听我的某个属性怎么做呢?

    有一个做法,hook 掉系统的 addObserver 方法,在这里判断 keyPath 是否是不想让监听的属性。

    具体代码如下:

    #import <objc/runtime.h>
    
    @implementation NSObject (CYKVO)
    
    + (void)load
    {
        [self switchMethod];
    }
    
    // 交换后的方法
    - (void)cy_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context
    {
        @try {
            if ([keyPath isEqualToString:@"can_not_observer_name"]) {
                return;
            }
            [self cy_addObserver:observer forKeyPath:keyPath options:options context:context];
        } @catch (NSException *exception) {}
    }
    
    + (void)switchMethod
    {
        SEL cyAddSel = @selector(cy_addObserver:forKeyPath:options:context:);
        SEL sysAddSel = @selector(addObserver:forKeyPath:options:context:);
        
        Method cyAddMethod = class_getClassMethod([self class],cyAddSel);
        Method sysAddMethod = class_getClassMethod([self class], sysAddSel);
        
        method_exchangeImplementations(cyAddMethod, sysAddMethod);
    }
    
    @end
    

    具体使用场景可能是这样的:
    有一个类是这样写的:

    //.h
    @interface Person : NSObject
    
    @property (nonatomic, strong) NSString *can_not_observer_name;
    
    @end
    
    
    //.m
    @implementation Person
    
    -(instancetype)init {
        self = [super init];
        self.can_not_observer_name = @"name";
        
        return self;
    }
    
    @end
    
    

    在某个 VC 里这样使用:

    @interface ViewController ()
    @property (nonatomic, strong)Person *person;
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        self.person = [[Person alloc] init];
        [self.person addObserver:self forKeyPath:@"can_not_observer_name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
    }
    
    -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
        NSLog(@"observeValueForKeyPath");
    }
    
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        self.person.can_not_observer_name = @"set a new value";
    }
    
    @end
    
    

    这样是监听不到 can_not_observer_name 这个属性的。

    相关文章

      网友评论

        本文标题:iOS 反 KVO(如何知道属性被监听了)

        本文链接:https://www.haomeiwen.com/subject/lanczxtx.html