許多編程技術(shù)都基于間接機(jī)制荔仁,包括整個面向?qū)ο缶幊填I(lǐng)域售貌。鍵值編碼也是一種間接機(jī)制育特,這種機(jī)制不屬于Objective-C語言的特性丙号,而是Cocoa提供的一種特性。
我們可以通過直接調(diào)用方法缰冤、屬性的點表示法或設(shè)置實例變量來直接更改對象狀態(tài)犬缨。鍵值編碼是一種間接更改對象狀態(tài)的方式,稱其為KVC棉浸,其實現(xiàn)方法是使用字符串表示要更改的對象狀態(tài)怀薛。
一些更加高級的Cocoa特性,比如CoreData和CocoaBindings迷郑,也在基礎(chǔ)機(jī)制中使用了KVC功能枝恋。
1 入門項目
2 KVC簡介
鍵/值編碼中的基本調(diào)用是 -valueForKey:和-setValue:forKey:方法。你可以向?qū)ο蟀l(fā)送消息嗡害,并傳遞你想要訪問的屬性名稱的鍵作為參數(shù)焚碌。
我們可以通過如下方法訪問對象的屬性:
valueForKey:的功能非常強(qiáng)大,它可以找到相關(guān)屬性的值并將其返回霸妹。
valueForKey:會首先查找以參數(shù)名命名(格式為-key或-isKey)的getter方法十电。對于以上前兩個調(diào)用,valueForKey:會先尋找-name和-make方法抑堡。如果沒有這樣的getter方法摆出,它將會在對象內(nèi)尋找名稱格式為_key或key的實例變量。
非常重要的一點:-valueForKey在Objective-C運(yùn)行時中使用元數(shù)據(jù)打開對象并進(jìn)入其中查找需要的信息首妖。在C或C++語言中不能執(zhí)行這種操作偎漫。通過使用KVC,沒有相關(guān)getter方法也能獲取對象值,不需要通過對象指針來直接訪問實例變量有缆。
對于KVC, Cocoa會自動裝箱和開箱標(biāo)量值象踊。也就是說,當(dāng)使用setValueForKey時棚壁,它會自動將標(biāo)量值(int杯矩、float和struct)放入NSNumber或NSValue中;當(dāng)使用-setValueForKey時袖外,它自動將標(biāo)量值從這些對象中取出史隆。僅KVC具有這種自動裝箱功能,常規(guī)方法調(diào)用和屬性語法不具備該功能曼验。
除了檢索值外泌射,還可以使用-setValue:forKey:方法依據(jù)名稱設(shè)置值粘姜。
以上方法的工作方式與-valueForKey:相同。它先查找名稱的setter方法熔酷,然后調(diào)用它并傳遞參數(shù)孤紧。如果不存在setter方法,它將在類中尋找名為key或_key的實例變量拒秘,然后為它賦值号显。
編譯器和蘋果公司都以下劃線開頭的形式保存實例變量名稱,所以躺酒,你最好遵守這條規(guī)則押蚤,不要在其他地方使用下劃線。
如果你想設(shè)置一個標(biāo)量值阴颖,在調(diào)用-setValue:forKey:方法之前需要將它們包裝起來活喊,也就是裝箱到對象中,而對于KVC的賦值方法量愧,Cocoa會自動開箱先取標(biāo)量值钾菊,再賦值。
3.鍵路徑
表示鍵路徑:可以在不同的變量名稱之間用圓點分開偎肃。
這些鍵路徑的深度是任意的煞烫,具體取決于對象圖(object graph, 可以表示對象之間的關(guān)系)的復(fù)雜度,可以使用諸如car.interior.airconditioner.fan.velocity這樣的鍵路徑累颂。在某種程度上滞详,使用鍵路徑比使用一系列嵌套方法調(diào)用更容易訪問到對象。
4.整體操作
關(guān)于KVC非常棒的一點是紊馏,如果使用某個鍵值來訪問一個NSArray數(shù)組料饥,它實際上會查詢相應(yīng)數(shù)組中的每個對象,然后將查詢結(jié)果打包到另一個數(shù)組中并返回給你朱监。這種方法也同樣適用于通過鍵路徑訪問的位于對象中的數(shù)組岸啡。
在KVC中,通常認(rèn)為對象的NSArray具有一對多的關(guān)系赫编。如果鍵路徑中含有一個數(shù)組屬性巡蘸,則該路徑的其余部分將被發(fā)送給數(shù)組中的每個對象。(第二句話后一部分的理解: NSArray數(shù)組實現(xiàn)valueForKeyPath:的方法是循環(huán)遍歷它的內(nèi)容并向每個對象發(fā)送消息擂送。因此NSArray向每個在自身之中的對象發(fā)送了參數(shù)以剩余部分作為鍵路徑的valueForKeyPath:消息悦荒,結(jié)果就將數(shù)組中每個對象對應(yīng)的屬性值放到數(shù)組中返回)。
鍵路徑的缺點: 不幸的是嘹吨,不能在鍵路徑中索引對象的數(shù)組搬味,比如說獲取對象的數(shù)組中的第一個被包含對象的屬性值。
一對一關(guān)系,一般對象的復(fù)合都是一對一關(guān)系身腻。
4.1 休息一下
懶加載也可以稱之為惰性初始化产还,僅在需要時才去創(chuàng)建它匹厘。這是編程技術(shù)的一種思想嘀趟。
4.2 快速運(yùn)算
鍵路徑不僅能引用對象值,還可以引用一些運(yùn)算符來進(jìn)行一些運(yùn)算愈诚,例如能獲取一組值的平均值或返回這組值中的最小值和最大值她按。
注意:上述代碼中的@count, 其中@符號意味著后面將進(jìn)行一些運(yùn)算。對編譯器來說炕柔,@"blah"是一個字符串酌泰,而@interface用于聲明類。此處的@count用于通知KVC機(jī)制計算鍵路徑左側(cè)值的對象總數(shù)匕累。而@sum陵刹、@avg、@min欢嘿、@max衰琐、@distinctUnionOfObjects等運(yùn)算符將鍵路徑分成兩部分。第一部分可以看成一對多關(guān)系的鍵路徑炼蹦,另一部分可以看成任何包含一對多關(guān)系的鍵路徑羡宙。它被當(dāng)作用于關(guān)系中每個對象的鍵路徑。(獲取左側(cè)指定的集合掐隐,對該集合中的每個對象使用右側(cè)的鍵路徑狗热,然后將結(jié)果轉(zhuǎn)換為一個集合。名稱中的union指一組對象的并集虑省,distince用于刪除重復(fù)內(nèi)容匿刮。KVC還支持多種運(yùn)算符,可供自己探索探颈,不過遺憾的是熟丸,你無法添加自己的運(yùn)算符。
KVC的功能非常強(qiáng)大膝擂,可以非常輕松地處理集合類虑啤,似乎完全可以取代對象的存取方法和其他代碼編寫。但是KVC有以下兩個缺點:
① KVC需要解析字符串來計算你需要的答案架馋,因此速度比較慢狞山。
② 編譯器無法對鍵路徑進(jìn)行錯誤檢查。當(dāng)你嘗試使用它時叉寂,一旦出現(xiàn)鍵路徑錯誤萍启,程序直接crash掉。
個人意見:一般情況下,通過對象的存取方法和其他代碼實現(xiàn)不了相應(yīng)的功能時勘纯,再考慮使用KVC局服。
-
批處理
KVC包含兩個調(diào)用, 一個可以批量獲取,另一個可以批量更改驳遵。
注意:集合類對象中不能包含nil值淫奔,因為nil是集合類對象的終止符號,若包含堤结,則會引起非法參數(shù)異常程序crash唆迁。在OC中,我們一般使用[NSNull null]表示nil值竞穷。
-
nil仍然可用
雖然nil不可在集合類對象中使用唐责,但仍然可在KVC賦值中使用,而對于屬性標(biāo)量值設(shè)置為nil程序crash的問題有辦法解決瘾带。
注意:如果得到了一個意外之料的鍵鼠哥,我們可以調(diào)用超類方法。
一般來說看政,除非你有某些特殊的原因朴恳,比如不想執(zhí)行某個操作,否則應(yīng)該總是在重寫的代碼中調(diào)用超類的方法帽衙。 -
處理未定義的鍵
使用KVC菜皂,處理未定義的鍵,需要重寫相關(guān)的方法厉萝。如果KVC機(jī)制無法找到處理方式恍飘,會退回并詢問該類如何處理。默認(rèn)的實現(xiàn)會取消操作谴垫,但是我們可以更改默認(rèn)的行為章母。
注意:
① <null>為后端返回數(shù)據(jù),或者控制臺打印翩剪,<null>是一種[NSNull null]對象乳怎。所以,當(dāng)服務(wù)端返回<null>前弯,前端可用[NSNull null]來進(jìn)行判斷蚪缀;(null) 是一個真正的nil值,所以恕出,同樣询枚,移動端可用nil值來判斷服務(wù)端端返回的(null)。
② 對于字典浙巫,使用KVC的賦值方法(setValue:forKey:)金蜀,調(diào)用者可以直接傳入nil值刷后。而如果為字典的setObject:forKey:提供nil值,它將會給出警告信息渊抄,程序crash尝胆。其實,對于后臺返回的數(shù)據(jù)或者用戶輸入的數(shù)據(jù)护桦,在提交字典參數(shù)請求服務(wù)端時都必須進(jìn)行非空判斷含衔,最好的辦法是在程序中每一處進(jìn)行非空判斷,另外一種辦法:可以嘗試使用runtime解決嘶炭。
③ 如果在字典中對setValue:forKey:方法傳入nil值抱慌,可能會把對應(yīng)鍵的值從字典中刪除。但即使這樣眨猎,在kvc中,nil值仍然可用强经。
小結(jié):
① KVC通過查找setter和getter方法來使用單個鍵設(shè)置值或者獲取值睡陪。如果KVC無法找到任何方法,將直接進(jìn)入對象并更改值匿情。
② 鍵路徑:它們是由點分割的鍵兰迫,用于在對象的網(wǎng)絡(luò)中指定路徑。也許這些鍵路徑看起來很像訪問屬性炬称,但實際上它們是兩種完全不同的機(jī)制汁果。可以將各種運(yùn)算符嵌入到鍵路徑中玲躯,以使KVC實現(xiàn)其他功能据德。
③ 通過重寫系統(tǒng)方法可以定制個別行為。