KVC
kvc提供了一種在運(yùn)行時(shí)而非編譯時(shí)動(dòng)態(tài)訪問對(duì)象屬性與成員變量的方式,該方法不需要調(diào)用get/set方法
OC中訪問變量的方式
- _name 直接訪問
- self.name 利用屬性訪問
- [self setValue:@"" forKey:@""] KVC
[self valueForKey:@"someKey"];
查找過程:
1.查找對(duì)象是否帶有someKey這個(gè)方法
2.查找對(duì)象是否代用someKey這個(gè)實(shí)例變量(iVar)
3.調(diào)用 -(id)valueForUndefinedKey
4.拋出NSUndefinedKeyException異常
KVC內(nèi)部實(shí)現(xiàn)
一個(gè)對(duì)象在調(diào)用setValue時(shí)
1.根據(jù)方法名找到運(yùn)行方法的時(shí)候所需要的環(huán)境參數(shù)
2.從自己的isa指針結(jié)合環(huán)境參數(shù),找到具體的方法實(shí)現(xiàn)的接口下翎,isa指針同云,指向維護(hù)分發(fā)表的對(duì)象的類心俗,該分發(fā)表實(shí)際上包含了指向?qū)崿F(xiàn)類中的方法的指針
3.直接查找得來的具體的方法實(shí)現(xiàn)
@interface LBKVC : NSObject {
NSString *firstName;
}
@property (nonatomic, strong) NSString *lastName;
@end
[_kvc setValue:@"dog" forKey:@"lastName"]; // 屬性 會(huì)觸發(fā) set 方法
[_kvc setValue:@"cat" forKey:@"firstName"]; // 成員變量 沒有set方法
KVO
KVO主要用來解耦
在上面介紹的KVC機(jī)制上加上KVO的自動(dòng)觀察消息通知機(jī)制就水到渠成了吠勘。
*KVO是基于runtime機(jī)制實(shí)現(xiàn)的
*當(dāng)某個(gè)類的屬性對(duì)象被觀察時(shí)逸寓,系統(tǒng)會(huì)在運(yùn)行期動(dòng)態(tài)地創(chuàng)建該類的一個(gè)派生類若治,在這個(gè)派生類中重寫基類中任何被觀察屬性的setter方法慨蓝。派生類在被重寫的setter方法內(nèi)實(shí)現(xiàn)真正的通知機(jī)制
*如果原來類為Person,那么生成的派生類名為NSKVONotifying_Person
*每個(gè)類對(duì)象中都有一個(gè)isa指針指向當(dāng)前類感混,當(dāng)一個(gè)類對(duì)象被觀察,那么系統(tǒng)會(huì)偷偷將isa指針指向動(dòng)態(tài)生成的派生類礼烈,從而在給被監(jiān)控屬性賦值時(shí)執(zhí)行的是派生類的setter方法
*鍵值觀察通知 依賴于NSObject的兩個(gè)方法 willChangeValueForKey 和 didChangeValueForKey 弧满。在一個(gè)被觀察屬性發(fā)生改變之前,willChangeValueForKey 一定會(huì)被調(diào)用此熬,這樣就會(huì)記錄舊的值庭呜,而當(dāng)值改變后,didChangeValueForKey 會(huì)被調(diào)用犀忱,繼而observeValueForKey:ofObject:change:context:也會(huì)被調(diào)用
// 手動(dòng)觸發(fā)
[self willChangeValueForKey:@"name"];
[self didChangeValueForKey:@"name"];