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

在 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 这个属性的。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 最近项目中处理kvo 的时候,遇到一个问题:当我操作的时候,会发现kvo 释放的时候,会崩溃, 崩溃日志如下: /...
    那是一阵清风_徐来阅读 5,506评论 0 11
  • 1.自定义控件 a.继承某个控件 b.重写initWithFrame方法可以设置一些它的属性 c.在layouts...
    圍繞的城阅读 3,533评论 2 4
  • KVO 作为 iOS 中一种强大并且有效的机制,为 iOS 开发者们提供了很多的便利;我们可以使用 KVO 来检测...
    JzRo阅读 1,001评论 0 2
  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,853评论 0 9
  • 晚饭下午4.30出发,吃完5点多点,眼镜痒,拿出手机,点开自拍模式,发现,起!针!眼!了! 上次大概是初中的时候了...
    丁壮壮阅读 271评论 2 0