在 iOS 開發(fā)中監(jiān)聽一個對象的某個屬性,很容易做到昆箕,然后有時候我們在寫一些安全性的代碼或者框架時梭伐,不想讓別人監(jiān)聽我的某個屬性怎么做呢?
有一個做法抑堡,hook 掉系統(tǒng)的 addObserver 方法,在這里判斷 keyPath 是否是不想讓監(jiān)聽的屬性。
具體代碼如下:
#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
這樣是監(jiān)聽不到 can_not_observer_name 這個屬性的调衰。