KVC講解
- 2020 年 4 月 9 日
- 筆記
今天趁著項目bug修復完了,來講解一下OC知識的另一個技術點-KVC!針對KVC,講解兩個知識點
- 通過KVC修改屬性會觸發KVO么?
- KVC的賦值過程是怎樣的?原理是什麼?
- KVC的取值過程是怎樣的?原理是什麼?
一、問:通過KVC修改屬性會觸發KVO么?
答:會觸發KVO
創建工程項目TestKVO,ZXYPerson類有一個屬性age,在控制器ViewController中添加屬性觀察者KVO,項目程式碼如下
@interface ViewController ()
@property(nonatomic,strong) ZXYPerson *p; @end
@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; _p = [[ZXYPerson alloc]init]; _p.age = 10; [_p addObserver:self forKeyPath:@"age" options: NSKeyValueObservingOptionNew context:nil]; [_p setValue:@12 forKeyPath: @"age"]; } -(void)dealloc { [_p removeObserver:self forKeyPath:@"age"]; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{ NSLog(@"*********%@", change); }
上面橙色文字通過KVC方式更改屬性的值,將上面程式碼運行結果如下:
通過上面發現setValue:forKeyPath觸發了KVO,同理髮現setValue:forKey也會觸發KVO,但是這兩個方法有什麼區別呢?
setValue:forKeyPath會一層一層的(沿著路徑)向下找,然而setValue:forKey並不會這樣!(假如ZXYPerson養了一隻貓,貓有age屬性 ,通過”_p.cat.age”設置應該用setValue:forKeyPath,不能用setValue:forKey)
思考: 為什麼KVC更改屬性值會觸發KVO?那就需要講解下面知識。
二、問:KVC的賦值過程是怎樣的?原理是什麼?
setValue:forKey:的原理
accessInstanceVariablesDirectly方法的默認返回值是YES
下面一一驗證上面的順序:
驗證setValue:forkey調用過程不需要用到KVO,去除多餘的程式碼之後,簡化成如下:
#import "ViewController.h" #import "ZXYPerson.h" @interface ViewController () @property(nonatomic,strong) ZXYPerson *p; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; _p = [[ZXYPerson alloc]init]; [_p setValue:@12 forKeyPath: @"age"]; } @end #import "ZXYPerson.h" @implementation ZXYPerson - (void) setAge:(int)age { NSLog(@"調用了setAge方法"); } - (void) _setAge: (int)age { NSLog(@"調用了_setAge方法"); } @end
去除了age屬性的聲明,看看KVC賦值的前期過程(按照setKey, _setKey方法走)
同時寫了兩個方法,優先調用setAge方法,假如將setAge方法注釋掉
注釋掉setAge方法後,久調用了_setAge方法,證實了KVC的前期賦值情況!
如果兩個方法都沒有實現,此時KVC會看accessInstanceVariablesDirectly方法,返回Yes代表可以直接訪問成員變數,反之不能訪問成員變數!
如果返回為Yes,會按照_key、_isKey、key、isKey成員屬性進行賦值
此時像上面的程式碼加入這四個成員變數,如下(前提accessInstanceVariablesDirectly方法返回Yes)
@interface ZXYPerson : NSObject { @public int _age; int _isAge; int age; int isAge; } @end
加入上述程式碼,運行
首先給_age賦值,當四個成員變數同時出現,假如將int _age成員變數注釋掉,如下:
發現當_age注釋掉之後,優先給_isAge賦值,優先順序僅次於_age,假如將_isAge注釋掉之後
發現給age賦值,同理將age成員變數注釋掉之後
最後給isAge賦值,符合了上述setValue:forkey的訪問屬性的優先順序 _key > _isKey > key > isKey的順序
如果這四個成員變數都沒有了,就會報異常
通過上面講述知道setValue:forKey會觸發KVO
[_p setValue:@12 forKeyPath: @”age”]內部調用相當於
[p willChangeValueForKey @”age”]
p->_age = 12;
[p didChangeValueForKey @”age”]
所以會觸發KVO
以上就是setValue:forKey的賦值所有過程,希望大家再看看上述圖,下面講述KVC如何取值?
三、問: KVC的取值過程是怎樣的?原理是什麼?
valueForKey:的原理
下面一一驗證上面的順序:
@interface ZXYPerson : NSObject{ @public int _age; } @implementation ZXYPerson - (int)getAge { return 11; } - (int)age { return 12; } - (int)isAge { return 13; } - (int)_age { return 14; } @end @interface ViewController () @property(nonatomic,strong) ZXYPerson *p; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; _p = [[ZXYPerson alloc]init]; _p->_age = 10; NSLog(@"******%@",[_p valueForKey:@"age"]); } @end
看看KVC取值的前期過程(按照getAge > age > isAge > _age 方法走)
當有四個方法時,會優先調用getAge方法,如上面一樣列印出11,調用了getAge方法!假如把getAge()方法注釋掉,運行程式碼:
將getAge()方法注釋掉後,調用了age方法,驗證了getAge > age !假如把age方法注釋掉
將getAge()和age()方法注釋掉後,調用了isAge()方法,驗證了getAge > age > isAge !假如把isAge()方法注釋掉
將getAge()和age()方法以及isAge()注釋掉後,調用了_age()方法,驗證了getAge > age > isAge > _age!
如果四個方法都沒有實現,此時KVC會看accessInstanceVariablesDirectly方法,返回Yes代表可以直接查找成員變數,反之不能查找成員變數!
如果返回為Yes,會按照_key、_isKey、key、isKey成員屬性順序查找成員變數
此時像上面的程式碼加入這四個成員變數,如下(前提accessInstanceVariablesDirectly方法返回Yes,去除四個方法)
@public int _age; int _isAge; int age; int isAge;
加入了四個成員變數,控制器ViewController加入設置屬性的四個值的
_p->_age = 11; _p->_isAge = 12; _p->age = 13; _p->isAge = 14;
觀察成員變數的查找順序!驗證_key、_isKey、key、isKey
ZXYPerson有四個成員變數,當向著上面程式碼書寫,運行程式碼結論是11,對應著_age這個成員變數,所以優先取值_age!當將 _age成員變數注釋掉以及賦值注釋掉後
發現運行結果為12,對應的結果時_isAge, 得出結論 _age > _isAge! 繼續將_isAge成員變數注釋掉以及賦值_isAge如下:
發現運行結果為13,對應的結果時age, 得出結論 _age > _isAge > age! 繼續將age成員變數注釋掉以及賦值age如下:
發現運行結果為14,對應的結果時isAge, 得出結論 _age > _isAge > age > isAge! 繼續將isAge成員變數注釋掉以及賦值isAge如下:
如果都注釋掉,會報異常valueForUndefinedKey錯誤!
以上就是valueForKey的取值所有過程,希望大家再看看上述圖回顧KVC如何取值!
上述就是KVC的基本內容,希望對大家有所幫助,可以關注部落格會實時更新,謝謝!!!