前言
最近一直在做原型圖,中間有兩天沒有寫簡書了当叭。感覺心里面特別不是滋味茬故。所以今天好不容易忙中偷閑,所以今天必須寫幾篇簡書蚁鳖,安慰一下自己的內(nèi)心磺芭。于是今天給大家分享一下KVC和KVO的簡單用法,隨后會更加深層次的去寫一系列的簡書醉箕,去深層次的講解KVC和KVO钾腺。
KVC用法
KVC也就是key-value-coding(鍵值編碼)徙垫,簡而言之就是通過key值去進行賦值和取值。主要是是操作對象的屬性放棒。以下是幾個常用的方法:
- setValue:forKey:(為對象的屬性賦值)
- setValue: forKeyPath:(為對象的屬性賦值(包含了setValue:forKey:的功能姻报,并且還可以對對象內(nèi)的類的屬性進行賦值))
- valueForKey:(根據(jù)key取值)
- valueForKeyPath:(根據(jù)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中調(diào)用
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);
}
有幾個小點,我也是在敲代碼的時候發(fā)現(xiàn)的间螟。
- 在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;你會發(fā)現(xiàn)value的值必須是id,也就是說不能傳基本數(shù)據(jù)類型,必須是指針類型的變量见坑。
KVC和對象的setter仙辟、getter方法的區(qū)別
一般情況下,KVC和setter鳄梅、getter應該說都能達到對對象屬性的賦值叠国,并且KVC操作也是去調(diào)用的setter方法和getter方法(針對一些已經(jīng)在.h中聲明的屬性而言)。但是對于一些私有屬性戴尸,那么這個時候setter粟焊、getter方法就沒有用了,這個時候KVC卻能發(fā)揮重要優(yōu)勢孙蒙。
例如:在Person.m中
#import "Person.h"
@implementation Person
{
NSInteger _height;
}
@end
此時你會發(fā)現(xiàn)setter项棠、getter已經(jīng)無能為力了,但是KVC去可以實現(xiàn)賦值挎峦、取值
[p setValue:@170 forKey:@"height"];
key和keyPath的區(qū)別
keyPath方法是集成了key的所有功能香追,也就是說對一個對象的一般屬性進行賦值、取值坦胶,兩個方法是通用的透典,都可以實現(xiàn)。但是對對象中的對象進的屬性行賦值顿苇,只有keyPath能夠?qū)崿F(xiàn)峭咒。
setValuesForKeysWithDictionary:的巧妙使用(字典轉(zhuǎn)模型)
-(instancetype)initWithDict:(NSDictionary *)dict{
if (self = [super init]) {
[self setValuesForKeysWithDictionary:dict];
}
return self;
}
注意點:
- 字典轉(zhuǎn)模型的時候,字典中的某一個key一定要在模型中有對應的屬性
- 如果一個模型中包含了另外的模型對象,是不能直接轉(zhuǎn)化成功的。
- 通過kvc轉(zhuǎn)化模型中的模型,也是不能直接轉(zhuǎn)化成功的纪岁。
KVO的用法
KVO也就是key-value-observing(即鍵值觀察),利用一個key來找到某個屬性并監(jiān)聽其值得改變凑队。用法如下:
- 添加觀察者
- 在觀察者中實現(xiàn)監(jiān)聽方法,observeValueForKeyPath: ofObject: change: context:(通過查閱文檔可以知道幔翰,絕大多數(shù)對象都有這個方法漩氨,因為這個方法屬于NSObject)
- 移除觀察者
//讓對象b監(jiān)聽對象a的name屬性
//options屬性可以選擇是哪個
/* NSKeyValueObservingOptionNew =0x01, 新值
* NSKeyValueObservingOptionOld =0x02, 舊值
*/
[a addObserver:b forKeyPath:@"name"options:kNilOptionscontext:nil];
a.name = @"zzz";
#pragma mark - 實現(xiàn)KVO回調(diào)方法
/* * 當對象的屬性發(fā)生改變會調(diào)用該方法
* @param keyPath 監(jiān)聽的屬性
* @param object 監(jiān)聽的對象
* @param change 新值和舊值
* @param context 額外的數(shù)據(jù)
*/
- (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指針,會在隨后的簡述中介紹)
當一個類的屬性被觀察的時候叫惊,系統(tǒng)會通過runtime動態(tài)的創(chuàng)建一個該類的派生類款青,并且會在這個類中重寫基類被觀察的屬性的setter方法,而且系統(tǒng)將這個類的isa指針指向了派生類赋访,從而實現(xiàn)了給監(jiān)聽的屬性賦值時調(diào)用的是派生類的setter方法。重寫的setter方法會在調(diào)用原setter方法前后缓待,通知觀察對象值得改變蚓耽。
??具體實現(xiàn)圖如下,這里我拿的是iOS程序猿的圖旋炒,借用一下應該沒關系吧步悠?
今天僅僅是KVO和KVC的簡單的用法的介紹,隨后會更加深層次的進行介紹瘫镇,敬請期待.....鼎兽、
歡迎關注我的個人微信公眾號,免費送計算機各種最新視頻資源铣除!你想象不到的精彩谚咬!