前言
最近一直在做原型圖,中間有兩天沒有寫簡書了。感覺心里面特別不是滋味。所以今天好不容易忙中偷閑,所以今天必須寫幾篇簡書,安慰一下自己的內心。于是今天給大家分享一下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的簡單的用法的介紹,隨后會更加深層次的進行介紹,敬請期待.....、
歡迎關注我的個人微信公眾號,免費送計算機各種最新視頻資源!你想象不到的精彩!