博客> KVC/KVO常用方法及使用场景
KVC/KVO常用方法及使用场景
2019-07-17 20:38 评论:0 阅读:732 aa100056
ios kvo kvc

1. KVC常用方法:

1.1 赋值方法:

  • -(void)setValue:(nullable id)value forKey:(NSString *)key;
  • -(void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;
  • -(void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;
  • -(void)setValuesForKeysWithDictionary:(NSDictionary *)keyedValues;

1.2 取值方法:

// 能取得私有成员变量的值

  • -(id)valueForKey:(NSString *)key;
  • -(id)valueForKeyPath:(NSString *)keyPath;
  • -(id)valueForUndefinedKey:(NSString *)key;

2. KVC使用场景

Person person = [[Person alloc] init]; //name、dog、sex1为person的成员变量,kind为dog的成员变量 Dog dog = [[Dog alloc] init]; 1)setValue: forKey: 方法 [person setValue:@"张三" forKey:@"name"]; 2)setValue: forKeyPath: 方法 [person setValue:dog forKeyPath:@"dog.kind"]; 3)setValue: forUndefinedKey: 方法 当[person setValue:@"男性" forKey:@"sex1"];由于person没有sex1成员变量,只有sex成员变量,会报错; 因此需要在person类重写setValue: forUndefinedKey: 方法: -(void)setValue:(id)value forUndefinedKey:(NSString )key{ if ([key isEqualToString:@"sex1"]) { //将sex1的值赋值给_sex,或者不设值,即可避免报错 sex = value;}} 4) setValuesForKeysWithDictionary: 方法 //字典快速转化成模型 NSDictionary dic = @{@"name":@"张三",@"sex":@"男",@"age":@"22"}; [person setValuesForKeysWithDictionary:dic]; 注:当dic中存在模型没有的字段或者不同字段名时,会报运行时错误;可以通过重写setValue: forUndefinedKey: 方法,过滤不存在的键值对或重新赋值。 5) valueForKey: 方法 [person valueForKey:@"name"]; 6) valueForKeyPath: 方法 [person valueForKeyPath:@"dog.kind"] 7) valueForUndefinedKey:方法 //当取值的时候, 找不到相应的key, 会调用该方法 -(id)valueForUndefinedKey:(NSString *)key{ if ([key isEqualToString:@"sex1"]) { return _sex; }}

3. KVO实现步骤

*注册

//keyPath就是要观察的属性值 //options给你观察键值变化的选择 NSKeyValueObservingOptions: NSKeyValueObservingOptionNew 新值 NSKeyValueObservingOptionOld 旧值 NSKeyValueObservingOptionInitial 注册后立刻触发KVO通知 NSKeyValueObservingOptionPrior 2次回调,变化前后 //context上下文,这个会传递到订阅着的函数中,用来区分消息,所以应当是不同的 -(void)addObserver:(NSObject )anObserver forKeyPath:(NSString )keyPath options: (NSKeyValueObservingOptions)options context:(void *)context

*实现方法

//change里存储了一些变化的数据,比如变化前的数据,变化后的数据;如果注册时context不为空,这里context就能接收到。 -(void)observeValueForKeyPath:(NSString )keyPath ofObject:(id)object change:(NSDictionary )change context:(void *)context;

*移除

-(void)removeObserver:(NSObject )observer forKeyPath:(NSString )keyPath;

KVO注意事项

KVO的addObserver和removeObserver需要是成对的,如果重复remove则会导致NSRangeException类型的Crash,如果忘记remove则会在观察者释放后再次接收到KVO回调时Crash。 苹果官方推荐的方式是,在init的时候进行addObserver,在dealloc时removeObserver,这样可以保证add和remove是成对出现的,是一种比较理想的使用方式。

手动调用KVO

如果一个类(这个类指key所在的类)想要实现手动的change notification发送,则必须重写NSObject实现的automaticallyNotifiesObserversForKey:方法,并对需要实现手动发送的key返回NO,其余则调用super。 +(BOOL)automaticallyNotifiesObserversForKey:(NSString *)theKey { BOOL automatic = NO; if ([theKey isEqualToString:@"age"]) { automatic = NO; } else { automatic = [super automaticallyNotifiesObserversForKey:theKey]; } return automatic; } 然后在property的值改变之前调用willChangeValueForKey:,在值改变之后调用didChangeValueForKey:。当然,在什么样的情况下才调用这两个方法,是由第三方程序的逻辑决定的。 如果一个操作造成了多个key的值的改变,则willChangeValueForKey:和didChangeValueForKey:必须嵌套着调用。 -(void)setAge:(NSInteger)age{ if (age != _age) { [self willChangeValueForKey:@"age"]; _age = age;//第三方程序的逻辑处理 [self didChangeValueForKey:@"age"]; } }

收藏
1
sina weixin mail 回到顶部