KVC、KVO探识(一)KVO和KVO的详细使用
前言
最近一直在做原型图,中间有两天没有写简书了。感觉心里面特别不是滋味。所以今天好不容易忙中偷闲,所以今天必须写几篇简书,安慰一下自己的内心。于是今天给大家分享一下KVC和KVO的简单用法,随后会更加深层次的去写一系列的简书,去深层次的讲解KVC和KVO。
KVC用法
KVC也就是key-value-coding(键值编码),简而言之就是通过key值去进行赋值和取值。主要是是操作对象的属性。以下是几个常用的方法:
- setValue:forKey:(为对象的属性赋值)
- setValue: forKeyPath:(为对象的属性赋值(包含了setValue:forKey:的功能,并且还可以对对象内的类的属性进行赋值))
- valueForKey:(根据key取值)
- valueForKeyPath:(根据keyPath取值)
- setValuesForKeysWithDictionary:(对模型进行一次性赋值)
几种方法的详尽用法
例如:生成一个这样子的对象Person
person.h
@class Car;
@interface Person : NSObject
@property (nonatomic,copy) NSString *name;
@property (nonatomic,strong)Car *car;
@end
Car.h
@interface Car : NSObject
@property (nonatomic,strong) NSNumber *price;
@end
在ViewController.m中调用
ViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
Person *person=[[Person alloc]init];
[person setValue:@"lxh" forKey:@"name"];
float price=100.0;
Car *car=[[Car alloc]init];
person.car=car;
[person setValue:[NSNumber numberWithFloat:price] forKeyPath:@"car.price"];
NSLog(@"%@",person.name);
NSLog(@"%f",car.price.floatValue);
}
有几个小点,我也是在敲代码的时候发现的。
- 在Person中我仅仅只是声明了@class Car,而没有引用#import "Car.h",然后在ViewController.m中便可以对其进行: [person setValue:[NSNumber numberWithFloat:price] forKeyPath:@"car.price"];这样子的赋值。所以说明KVC会去自动查找Car类进行赋值。
- 在对person.car进行赋值的时候,必须保证car变量的存在,也就是说,必须生成一个Car对象赋值给person.car.否则会抛出野指针异常错误。
- 还有就是setValue:forKey:和setValue: forKeyPath:这两个方法,可以查看NSObject中的声明:- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;你会发现value的值必须是id,也就是说不能传基本数据类型,必须是指针类型的变量。
KVC和对象的setter、getter方法的区别
一般情况下,KVC和setter、getter应该说都能达到对对象属性的赋值,并且KVC操作也是去调用的setter方法和getter方法(针对一些已经在.h中声明的属性而言)。但是对于一些私有属性,那么这个时候setter、getter方法就没有用了,这个时候KVC却能发挥重要优势。
例如:在Person.m中
#import "Person.h"
@implementation Person
{
NSInteger _height;
}
@end
此时你会发现setter、getter已经无能为力了,但是KVC去可以实现赋值、取值
[p setValue:@170 forKey:@"height"];
key和keyPath的区别
keyPath方法是集成了key的所有功能,也就是说对一个对象的一般属性进行赋值、取值,两个方法是通用的,都可以实现。但是对对象中的对象进的属性行赋值,只有keyPath能够实现。
setValuesForKeysWithDictionary:的巧妙使用(字典转模型)
-(instancetype)initWithDict:(NSDictionary *)dict{
if (self = [super init]) {
[self setValuesForKeysWithDictionary:dict];
}
return self;
}
注意点:
- 字典转模型的时候,字典中的某一个key一定要在模型中有对应的属性
- 如果一个模型中包含了另外的模型对象,是不能直接转化成功的。
- 通过kvc转化模型中的模型,也是不能直接转化成功的。
KVO的用法
KVO也就是key-value-observing(即键值观察),利用一个key来找到某个属性并监听其值得改变。用法如下:
- 添加观察者
- 在观察者中实现监听方法,observeValueForKeyPath: ofObject: change: context:(通过查阅文档可以知道,绝大多数对象都有这个方法,因为这个方法属于NSObject)
- 移除观察者
//让对象b监听对象a的name属性
//options属性可以选择是哪个
/* NSKeyValueObservingOptionNew =0x01, 新值
* NSKeyValueObservingOptionOld =0x02, 旧值
*/
[a addObserver:b forKeyPath:@"name"options:kNilOptionscontext:nil];
a.name = @"zzz";
#pragma mark - 实现KVO回调方法
/* * 当对象的属性发生改变会调用该方法
* @param keyPath 监听的属性
* @param object 监听的对象
* @param change 新值和旧值
* @param context 额外的数据
*/
- (void)observeValueForKeyPath:(NSString *)keyPathofObject:(id)objectchange:(NSDictionary<NSString *,id>*)change context:(void *)context{
NSLog(@"%@的值改变了,",keyPath);
NSLog(@"change:%@", change);
}
//最后不要忘记了,去移除observer
- (void)dealloc{
[a removeObserver:b forKeyPath:@"name"];
}
KVO底层(这部分涉及到了runtime,关于isa指针,会在随后的简述中介绍)
当一个类的属性被观察的时候,系统会通过runtime动态的创建一个该类的派生类,并且会在这个类中重写基类被观察的属性的setter方法,而且系统将这个类的isa指针指向了派生类,从而实现了给监听的属性赋值时调用的是派生类的setter方法。重写的setter方法会在调用原setter方法前后,通知观察对象值得改变。
具体实现图如下,这里我拿的是iOS程序猿的图,借用一下应该没关系吧?
今天仅仅是KVO和KVC的简单的用法的介绍,随后会更加深层次的进行介绍,敬请期待.....、
欢迎关注我的个人微信公众号,免费送计算机各种最新视频资源!你想象不到的精彩!
作者:Peak_One
链接:https://www.jianshu.com/p/ca5cf1610d34
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。