直入主題,開頭先介紹下本篇學習和探究方向,首先搞清楚成員變量、實例變量、屬性的定義,以便KVC賦值取值時可以輕鬆區分;其次深刻探究KVC取值原理、賦值原理;再次經過對YYmodel源碼的分析,深刻理解KVC;最後再探究一下Category的實現原理及其使用時的注意點。html
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
//{}內的所有爲成員變量,實例變量是一種特殊的成員變量,是由OC中的類聲明的成員變量
{
UIButton *button;
int count;
id data;
}
//GCC --> LLVM 屬性
//1.默認的setter + getter
//2.自動建立一個帶下劃線的實例變量匹配屬性
@property (nonatomic, strong) UIButton *myButton;
@end
@implementation ViewController
@synthesize myButton = _myButton; //指定與屬性對應的實例變量
編譯器期間,讓編譯器自動生成getter/setter方法。
當有自定義的存或取方法時,自定義會屏蔽自動生成該方法
@dynamic myButton;
告訴編譯器,不自動生成屬性對應的實例變量和訪問方法(getter/setter),避免編譯期間產生警告;
而後由本身實現存取方法或存取方法在運行時動態建立綁定
@end
複製代碼
在{ }中聲明的變量都是成員變量;按照上面的例子:button count data都是成員變量;ios
實例變量本質上就是成員變量,只是實例是針對類而言,實例是指類的聲明;git
按照上面的例子:button是實例變量 data也是實例變量,由於id是OC特有的類,本質上來講id等同於(void *);bash
實例變量的英文翻譯爲 Instance Variable (object-specific storage)app
實例的英文翻譯爲 Instance (manifestation of a class)說的是"類的表現",說明實例變量應該是由類定義的變量!ide
除去基本數據類型int float ....等,其餘類型的變量都叫作實例變量;學習
屬性變量的好處就是容許讓其餘對象訪問到該變量,由於屬性建立過程當中自動產生了set方法和get方法;固然,你能夠設置只讀或者可寫等,設置方法也可自定義。因此,屬性變量是用於與其餘對象交互的變量。ui
鍵值編碼是一種機制,經過NSKeyValueCoding非正式協議,對象採用這種機制提供對其屬性的間接訪問。當對象符合鍵值編碼時,它的屬性可使用字符串參數經過簡明、統一的消息接口進行尋址。這種間接訪問機制補充了實例變量及其關聯的訪問器方法提供的直接訪問。 Key-Value Coding Programming Guide 官方文檔編碼
set<Key>:
或_set<Key>:
的方法。若是找到, 傳入value值並調用。
set<Key>:``_set<Key>:
兩個方法,優先調用set<Key>:
方法;
set<Key>:
方法後,就調用了_set<Key>:
方法,證明了KVC的前期賦值狀況!
accessInstanceVariablesDirectly
返回YES, 則按如下順序查找實例變量:_<key>
、_is<Key>
、<key>
、is<Key>
。若是找到, 則直接使用value值設置變量並完成。
_key
賦值;
_key
成員變量註釋掉後,就優先給_isKey
賦值,優先級僅次於_key
;
_isKey
註釋掉以後,發現給key
賦值;
key
成員變量註釋掉以後,最後給isAge賦值,符合了上述setValue:forkey的訪問成員變量的優先級 _key > _isKey > key > isKey的順序。
setValue:forUndefinedKey:
。默認狀況下,這會引起異常,但NSObject的子類能夠經過重載並根據特定key作一些特殊處理。
get<Key>
、<key>
、is<Key>
或_<key>
的第一個訪問器方法。若是找到,調用它並繼續到步驟3。不然請繼續執行下一步。
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_p = [[YNPerson alloc]init];
NSLog(@"%@",[_p valueForKey:@"name"]);
}
@end
複製代碼
get<Key>
方法;
get<Key>
方法註釋掉後,調用了<key>
方法,驗證了get<Key>
><key>
;
get<Key>
和<key>
方法註釋掉後,調用了is<Key>
方法,驗證了get<Key>
> <key>
> is<Key>
;
get<Key>
和<key>
方法以及is<Key>
註釋掉後,調用了_<key>
方法,驗證了get<Key>
> <key>
> is<Key>
> _<key>
;
accessInstanceVariablesDirectly
返回YES,則系統按如下順序搜索名爲:_<key>
、_is<Key>
、<key>
或is<Key>
的實例變量。若是找到,則直接獲取實例變量的值,而後繼續執行步驟3。不然, 繼續跳轉到步驟4。
@interface YNPerson : NSObject
{
@public
NSString *_name;
NSString *_isName;
NSString *name;
NSString *isName;
}
@end
複製代碼
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_p = [[YNPerson alloc]init];
_p->_name = @"_name";
_p->_isName = @"_isName";
_p->name = @"name";
_p->isName = @"isName";
NSLog(@"%@",[_p valueForKey:@"name"]);
}
@end
複製代碼
_<key>
成員變量的值;
_<key>
成員變量時(註釋掉成員變量聲明和賦值),取_is<Key>
的值;
_<key>
和_is<Key>
成員變量時(註釋掉成員變量聲明和賦值),取<key>
的值;
_<key>
、_is<Key>
和<key>
成員變量時(註釋掉成員變量聲明和賦值),取is<Key>
的值;
valueForUndefinedKey:
。默認狀況下,這會引起異常,但NSObject的子類能夠經過重載並根據特定key作一些特殊處理。
關於此部份內容,請移步至YYModel 原理分析,歡迎查閱、指正。atom
關於此部份內容,請移步至Category的實現原理及其使用,歡迎查閱、指正。
因爲本人水平有限,文中若有不足之處,望大神指出。
若是你看完後以爲對你有所幫助,勿忘點贊
+關注
。
附本文的Demo,贈人玫瑰,手有餘香。