KVO里面的(void *)context
2018-11-13 本文已影响26人
Sweet丶
KVO中context介绍
一直使用KVO却很少关注context这个变量,这个变量来源于自己添加KVO监听的时候自己设置的
[self.phoneF addObserver:self forKeyPath:@"text" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:@"这里是自己定义的context"];// context是void *类型
// KVO下系统回调方法里的context = 上面自己添加时设置的context
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
if ([keyPath isEqualToString:@"text"] && object == self.phoneF) {
NSString *newNumber = change[NSKeyValueChangeNewKey];
NSString *oldNumber = change[NSKeyValueChangeOldKey];
if (![newNumber isEqualToString:oldNumber]) {
[self textField:object shouldChangeCharactersInRange:NSMakeRange(0, self.phoneF.text.length) replacementString:newNumber];
}
}else{
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
KVO的一种缺陷(其实不能称为缺陷,应该称为特性)是,当对同一个 keypath进行两次removeObserver时会导致程序crash,父类在dealloc中remove 了一次,子类又remove了一次.
这个时候就需要KVO移除监听时,只移除自己的KVO,方法就是添加监听时设置不同的context,移除时移除对应的context。
void *类型是什么
c语言中,void为“不确定类型”,不可以用void来声明变量。
// 对函数返回类型的限定和对函数参数限定:
void fun(int a);
int fun(void);
void * 为 “不确定类型指针”,声明为一个任何类型的变量
Facebook 封装得更好用
Facebook对KVO封装了一个类,使得KVO监听可以进行函数式回调,并且是自行移除监听
FBKVOController *KVOController = [FBKVOController controllerWithObserver:self];
self.KVOController = KVOController;
// observe clock date property
[self.KVOController observe:clock keyPath:@"date" options:NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionNew block:^(ClockView *clockView, Clock *clock, NSDictionary *change) {
// do some thing
}];
https://github.com/facebook/KVOController
项目中导入了RAC则使用RAC也很方便, 例子如下
[RACObserve(moneyF, text) subscribeNext:^(NSString *fieldText) {
// DLOG(@"moneyF.text = %@, x = %@", moneyF.text, fieldText);
if (fieldText.length == 0) {
NSMutableAttributedString *attrstring = [[NSMutableAttributedString alloc] initWithString:@"¥0.00" attributes:@{NSForegroundColorAttributeName:[UIColor colorWithHexString:@"#F0F0F0"]}];
[attrstring addAttribute:NSFontAttributeName value:[UIFont fontWithName:@"STHeitiSC-Light" size:40.f] range:NSMakeRange(0, 1)];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(.01 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.moneyF.attributedPlaceholder = attrstring;// 不延时则在输入框文字自适应调整大小之后点击右边清除按钮会使占位提示自动调整
});
}
}];