KVC: Key value coding
其实就是另一种形式的 getter setter. 引用一段kenshicui博客中的介绍:
KVC的操作方法由NSKeyValueCoding协议提供,而NSObject就实现了这个协议,也就是说ObjC中几乎所有的对象都支持KVC操作,常用的KVC操作方法如下:
- 动态设置:
setValue:属性值 forKey:属性名(用于简单路径)、
setValue:属性值 forKeyPath:属性路径(用于复合路径,例如Person有一个Account类型的属性,那么person.account就是一个复合属性)
动态读取:
valueForKey:属性名 、valueForKeyPath:属性名(用于复合路径)这里的Key值是类中属性变量的字符串。例如:有一个DIY类,有一个属性变量
@property (nonatomic,strong) NSArray *list;
, 那么他的path就是@“”
KVC用在给readonly变量赋值!
//有一个类名为 ACLStudent,他有一 个@property (nonatomic, copy, readonly) NSString *firstName;
ACLStudent *student = [[ACLStudent alloc] init];
[student setValue:@"Qiu" forKey:NSStringFromSelector(@selector(firstName))];
NSLog(@"student firstName after changed: %@", student.firstName);
通过这种方式可以给他的readonly变量赋值
KVO Key value observe 重点说一下KVO
通过添加观测者,在指定的KEY发生改变/设定时,使用回调函数。如下:
- 添加观察着用
- (void)addObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context
- 添加回调函数用
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
// 注册/添加观测者
-(void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(@"now KVO_View2 = %@",self.KVO_View2);
self.KVO_View2 = @"Goat shit";
[self addObserver:self
forKeyPath:@"KVO_View2"
options:NSKeyValueObservingOptionOld
context:NULL];
}
//......中间其他代码省略......
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{
if ([keyPath isEqualToString:@"KVO_View2"]) {
NSLog(@"Current KVO_View2 = %@",self.KVO_View2);
self.show.text = self.KVO_View2;
}
}
- 观察可变数组
muatableArray
的变化时候特别要注意的- 必须使用
self.goodsInfoArray
而不是_goodsInfoArray
才行
要替换成[self.goodsInfoArray addObject:goodsInfo];
[[self mutableArrayValueForKey:@"goodsInfoArray"] addObject:goodsInfo];
- 必须使用
才能监听到
- 顺便提一下,MJRefresh的下拉刷新,就是用KVO去监听
UIScrollView
的content offsetY
,当偏移量大于某一个值时,上面的frame下拉显示。
需要说明的几点是:
- 就目前来看,KVO多用于单个VC内部使用,用于多个VC跳转时会出现跳转过程,因为退出当前KV而KVO的observer没有remove而产生的错误
'An instance 0x7faa81d0c290 of class ForKVOViewController was deallocated while key value observers were still registered with it.
- KVO的观测只是观察path上的至是否被设置,而不能知道他是否和旧的值相同
- 关于option的几个值说明(待以后补充)
NSKeyValueObservingOptionNew
Indicates that the change dictionary should provide the new attribute value, if applicable.
NSKeyValueObservingOptionOld
Indicates that the change dictionary should contain the old attribute value, if applicable.
NSKeyValueObservingOptionInitial
If specified, a notification should be sent to the observer immediately, before the observer registration method even returns.
The change dictionary in the notification will always contain an NSKeyValueChangeNewKey entry if NSKeyValueObservingOptionNew is also specified but will never contain an NSKeyValueChangeOldKey entry. (In an initial notification the current value of the observed property may be old, but it's new to the observer.) You can use this option instead of explicitly invoking, at the same time, code that is also invoked by the observer's observeValueForKeyPath:ofObject:change:context: method. When this option is used withaddObserver:forKeyPath:options:context: a notification will be sent for each indexed object to which the observer is being added.
NSKeyValueObservingOptionPrior
Whether separate notifications should be sent to the observer before and after each change, instead of a single notification after the change.
The change dictionary in a notification sent before a change always contains an NSKeyValueChangeNotificationIsPriorKey entry whose value is [NSNumber numberWithBool:YES], but never contains an NSKeyValueChangeNewKey entry. When this option is specified the change dictionary in a notification sent after a change contains the same entries that it would contain if this option were not specified. You can use this option when the observer's own key-value observing-compliance requires it to invoke one of the -willChange... methods for one of its own properties, and the value of that property depends on the value of the observed object's property. (In that situation it's too late to easily invoke -willChange... properly in response to receiving an observeValueForKeyPath:ofObject:change:context: message after the change.)