KVC之-setValue:forKey:方法實(shí)現(xiàn)原理與驗(yàn)證

- (void)setValue:(id)value forKey:(NSString *)key方法,實(shí)現(xiàn)原理與驗(yàn)證

功能:使用一個(gè)字符串標(biāo)示符給一個(gè)對象的屬性賦值.它支持普通對象和集合對象
這個(gè)方法的默認(rèn)實(shí)現(xiàn)如下:

(1).首先去接收者(調(diào)用方法的那個(gè)對象)的類中查找與key相匹配的訪問器方法(-set<Key>),如果找到了一個(gè)方法,就檢查它參數(shù)的類型,如果它的參數(shù)類型不是一個(gè)對象指針類型,但是只為nil,就會執(zhí)行setNilValueForKey:方法,setNilValueForKey:方法的默認(rèn)實(shí)現(xiàn),是產(chǎn)生一個(gè)NSInvalidArgumentException的異常,但是你可以重寫這個(gè)方法.如果方法參數(shù)的類是一個(gè)對象指針類型,就會簡單的執(zhí)行這個(gè)方法,傳入對應(yīng)的參數(shù).如果方法的參數(shù)類型是NSNumberNSValue的對應(yīng)的基本類型,先把它轉(zhuǎn)換為基本數(shù)據(jù)類,再執(zhí)行方法,傳入轉(zhuǎn)換后的數(shù)據(jù).****


(2).如果沒有對應(yīng)的訪問器方法(setter方法),如果接受者的類的+accessInstanceVariablesDirectly方法返回YES,那么就查找這個(gè)接受者的與key相匹配的實(shí)例變量(匹配模式為_<key>,_is<Key>,<key>,is<Key>):比如:keyage,只要屬性存在_age,_isAge,age,isAge中的其中一個(gè)就認(rèn)為匹配上了,如果找到這樣的一個(gè)實(shí)例變量,并且的類型是一個(gè)對象指針類型,首先released對象上的舊值,然后把傳入的新值retain后的傳入的值賦值該成員變量,如果方法的參數(shù)類型是NSNumberNSValue的對應(yīng)的基本類型,先把它轉(zhuǎn)換為基本數(shù)據(jù)類,再執(zhí)行方法,傳入轉(zhuǎn)換后的數(shù)據(jù).



(3).如果訪問器方法和實(shí)例變量都沒有找到,執(zhí)行setValue:forUndefinedKey:方法,該方法的默認(rèn)實(shí)現(xiàn)是產(chǎn)生一個(gè) NSUndefinedKeyException 類型的異常,但是我們可以重寫setValue:forUndefinedKey:方法


驗(yàn)證:
定義一個(gè)Person類:如下


@interface Person : NSObject
{
    NSString *_name;
    int _age;
    NSString *_address;
}

@property (nonatomic, copy) NSString *name;

@property (nonatomic,assign) int age;

@end


@implementation Person


-(void)setName:(NSString *)name
{
    NSLog(@"%s----------%@",__func__,name);
   _name = name;
}

- (void) setAge:(int)age
{
    _age = age;

    NSLog(@"%s------%d",__func__,age);
}


- (int) age
{
    NSLog(@"%s------%d",__func__,_age);
    return _age;
}


- (NSString *) name
{
    NSLog(@"%s----------%@",__func__,_name);
    return _name;
}

@end

測試代碼
1)驗(yàn)證: setValue:forKey:確實(shí)會調(diào)用-set<Key>方法

    Person *p = [[Person alloc] init];
    [p setValue:@"小明" forKey:@"name"];

輸出結(jié)果

2015-08-15 20:56:56.975 company[1254:98490] -[Person setName:]----------小明
2015-08-15 20:56:56.975 company[1254:98490] -[Person setAge:]------10

2)驗(yàn)證:如果它的參數(shù)類型不是一個(gè)對象指針類型,但是只為nil,就會執(zhí)行setNilValueForKey:方法,setNilValueForKey:方法的默認(rèn)實(shí)現(xiàn),是產(chǎn)生一個(gè)NSInvalidArgumentException的異常
測試代碼
[p setValue:nil forKey:@"age"];
運(yùn)行結(jié)果:

2015-08-15 20:59:36.111 company[1300:100841]
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason:

3)可以重寫這個(gè)方法setNilValueForKey:
在Person類的實(shí)現(xiàn)文件中,重寫setNilValueForKey:

- (void) setNilValueForKey:(NSString *)key
{
    NSLog(@"%s",__func__);
}

再次運(yùn)行,結(jié)果:

2015-08-15 21:29:21.167 company[528:6226] -[Person setNilValueForKey:]

4)驗(yàn)證如果方法的參數(shù)類型是NSNumberNSValue的對應(yīng)的基本類型,先把它轉(zhuǎn)換為基本數(shù)據(jù)類,再執(zhí)行方法,傳入轉(zhuǎn)換后的數(shù)據(jù),測試代碼
Person.m 文件中:

- (void) setAge:(int)age
{
    _age = age;

    NSLog(@"%s------%d",__func__,age);
}

測試方法中

     [p setValue:@(10) forKey:@"age"];

執(zhí)行結(jié)果

2015-08-15 21:54:23.477 company[607:15602] -[Person setAge:]------10

5)驗(yàn)證如果如果沒有對應(yīng)的訪問器方法(setter方法),如果接受者的類的+accessInstanceVariablesDirectly方法返回YES,那么就查找這個(gè)接受者的與key相匹配的實(shí)例變量(匹配模式為_<key>,_is<Key>,<key>,is<Key>):比如:keyage,只要屬性存在_age,_isAge,age,isAge中的其中一個(gè)就認(rèn)為匹配上了,如果找到這樣的一個(gè)實(shí)例變量,并且的類型是一個(gè)對象指針類型,首先released對象上的舊值,然后把傳入的新值retain后的傳入的值賦值該成員變量,如果方法的參數(shù)類型是NSNumberNSValue的對應(yīng)的基本類型,先把它轉(zhuǎn)換為基本數(shù)據(jù)類,再執(zhí)行方法,傳入轉(zhuǎn)換后的數(shù)據(jù).
驗(yàn)證:+accessInstanceVariablesDirectly默認(rèn)返回YES
測試代碼

    NSLog(@"%d",[Person accessInstanceVariablesDirectly]);

輸出結(jié)果:

    2015-08-15 22:05:22.646 company[782:21098] 1

Person類中分別使用

@interface Person : NSObject
{
//    NSString *address;
//    NSString *_address;
//   注意is后面第一個(gè)字母必須大寫否則會產(chǎn)生NSUnknownKeyException異常
//    NSString *isAddress;
     NSString *_isAddress;

}

測試代碼

    NSLog(@"%d",[Person accessInstanceVariablesDirectly]);
    [p setValue:@"金燕龍大廈" forKey:@"address"];
    NSString *address = [p valueForKey:@"address"];

輸出結(jié)果:

    2015-08-15 22:05:22.646 company[782:21098] 金燕龍大廈

6)驗(yàn)證:如果訪問器方法和實(shí)例變量都沒有找到,執(zhí)行setValue:forUndefinedKey:方法,該方法的默認(rèn)實(shí)現(xiàn)是產(chǎn)生一個(gè) NSUndefinedKeyException 類型的異常,但是我們可以重寫setValue:forUndefinedKey:方法
測試代碼:

      [p setValue:@"美女" forKey:@"老婆"];

結(jié)果產(chǎn)生一個(gè)NSUnknownKeyException:

Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<Person 0x7fd0394a4c10> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key 老婆.'

Person.m文件中重寫 - (void)setValue:(id)value forUndefinedKey:(NSString *)key

- (void)setValue:(id)value forUndefinedKey:(NSString *)key
{
    NSLog(@"%s",__func__);
    NSLog(@"%@=%@",key,value);
}

再次運(yùn)行程序輸出結(jié)果:

2015-08-15 22:14:19.866 company[885:25268] -[Person setValue:forUndefinedKey:]
2015-08-15 22:14:19.866 company[885:25268] 老婆=美女
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子耗美,更是在濱河造成了極大的恐慌驶冒,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件废封,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)尿瞭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來翅睛,“玉大人声搁,你說我怎么就攤上這事〔斗ⅲ” “怎么了疏旨?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長扎酷。 經(jīng)常有香客問我檐涝,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任谁榜,我火速辦了婚禮幅聘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘窃植。我一直安慰自己帝蒿,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布巷怜。 她就那樣靜靜地躺著陵叽,像睡著了一般。 火紅的嫁衣襯著肌膚如雪丛版。 梳的紋絲不亂的頭發(fā)上巩掺,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天,我揣著相機(jī)與錄音页畦,去河邊找鬼胖替。 笑死,一個(gè)胖子當(dāng)著我的面吹牛豫缨,可吹牛的內(nèi)容都是我干的独令。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼好芭,長吁一口氣:“原來是場噩夢啊……” “哼燃箭!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起舍败,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤招狸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后邻薯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體裙戏,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年厕诡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了累榜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,117評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡灵嫌,死狀恐怖壹罚,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情寿羞,我是刑警寧澤猖凛,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站稠曼,受9級特大地震影響形病,放射性物質(zhì)發(fā)生泄漏客年。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一漠吻、第九天 我趴在偏房一處隱蔽的房頂上張望量瓜。 院中可真熱鬧,春花似錦途乃、人聲如沸绍傲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽烫饼。三九已至,卻和暖如春试读,著一層夾襖步出監(jiān)牢的瞬間杠纵,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工钩骇, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留比藻,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓倘屹,卻偏偏與公主長得像银亲,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子纽匙,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容