KVC和KVO的區(qū)別

KVC和KVO的區(qū)別

是在運行時動態(tài)的訪問和修改對象的屬性,它的定義是對NSObjcet的拓展實現(xiàn) KVO的依賴于OC的Runtime來實現(xiàn)的,當觀察者對象時,KVO機制動態(tài)創(chuàng)建一個對象A的子類(NSKVONotifying_A類),并為這個子類重寫了被觀察的屬性的setter方法,setter方**負責調(diào)用原來的setter方法前后,通知觀察對象發(fā)生了變化

什么是KVC和KVO?

KVC(Key-Value-Coding)內(nèi)部的實現(xiàn):一個對象在調(diào)用setValue的時候,(1)首先根據(jù)方法名找到運行方法的時候所需要的環(huán)境參數(shù)。(2)他會從自己isa指針結(jié)合環(huán)境參數(shù),找到具體的方法實現(xiàn)的接口。

(3)再直接查找得來的具體的方法實現(xiàn)。

KVO(Key-Value-Observing):當觀察者為一個對象的屬性進行了注冊,被觀察對象的isa指針被修改的時候,isa指針就會指向一個中間類,而不是真實的類。所以isa指針其實不需要指向?qū)嵗龑ο笳鎸嵉念?。所以我們的程?*不要依賴于isa指針。在調(diào)用類的方法的時候,**要明確對象實例的類名。

什么是KVC

在iOS開發(fā)過程中,我們經(jīng)常會聽到或者用到KVO/KVC,但是對于什么是KVO和KVC,我們可能沒有那么了解。下面先讓我們來了解一下什么是KVC. 什么是KVC 在蘋果的**文檔中是這樣描述KVC的:它是一種通過字符串描述符而不是通過調(diào)用訪問方法或者直接使用實例變量的非直接的訪問對象屬性的機制,說白了就是KVO是一種通過非常規(guī)方法訪問成員變量或者屬性的機制,這種非常規(guī)方式就是通過一個字符串標示符也就是所謂的key來訪問屬性或者成員變量。

而這個key一般就是屬性名或者實例變量名。

對于KVC的基本的方法都定義在NSKeyValueCoding的非正式協(xié)議中,并且NSObject默認實現(xiàn)了該協(xié)議。 KVC不僅支持對象類型,也支持數(shù)值類型和結(jié)構(gòu)體。非對象類型的參數(shù)和返回類型會自動封裝成NSValue或NSNumber類型。 KVO可以用來訪問三種不同的對象值類型:屬性、一對一關(guān)系、一對多關(guān)系 屬性可以是諸如數(shù)值、字符串、bool類型等簡單的值。

也可以NSNumber或者NSColor這樣的對象值。 在一對一關(guān)系里的對象可以擁有它自己的屬性,這些屬性可以在不改變對象的情況下被改變。像UIView的superView的屬性,我們可以更改superView的屬性,而不需要更改UIView。

一對多屬性是一些相關(guān)對象的**。通常用NSArray或者NSSet來存儲這些**。KVO也允許用戶自定義**類,但依然是像訪問NSArray或者NSSet一樣訪問它們。

鍵和鍵路徑 鍵是用來標識一個對象屬性的字符串。一般情況下,鍵就是訪問方法或者是對象的實例變量的名字。鍵必須是ASCII編碼,以小寫字母開頭,并且不能包含空格。

舉幾個鍵的例子:age、firstName、lastNmame等。 鍵路徑是一串由點分隔的鍵組成的字符串,它是用來遍歷一系列的對象屬性的。**個鍵的屬性是跟接收者相關(guān)的,而每一個子系列是跟前一個屬性相關(guān)的。比如鍵路徑address.street,這個鍵路徑會首先從接收者獲得address屬性,然后從address屬性中獲得street屬性。

用KVC獲得屬性的值 方法valueForKey:會返回跟接收者相關(guān)的key的值。如果對于指定的key沒有訪問器或者實例變量,則給自己發(fā)送一個valueForUndefinedKey:消息,這個方法的默認實現(xiàn)是拋出一個NSUndefinedKeyException。子類可以重寫這個方法。 同樣的,valueForKeyPath:返回跟接收者相關(guān)的鍵路徑的值。

對于子系列中任何不遵循KVC的對象,都會收到一個valueForUndefineKey:消息。 dictionaryWithValuesForKeys:會檢索數(shù)組中所有跟接收者相關(guān)的key的值。返回的NSDictionary中包含了數(shù)組中所有key的值。 注意:**對象,比如NSArray、NSSet和NSDictionary中不能將nil作為一個值。

相反的,應(yīng)該用NSNull對象代替nil。NSNull是一個代表nil的對象屬性。dictionaryWithValuesForKeys:和setValuesForKeysWithDictionary:方法的實現(xiàn)中,默認會在nil和NSNull之間進行轉(zhuǎn)換。

在你的對象中,不需要對nil做顯示的測試。 用KVC設(shè)置屬性的值 方法setValue:forKey:是將接收者中相關(guān)key的值設(shè)置成指定的值。在這個方法的實現(xiàn)中,會將NSValue的值轉(zhuǎn)換成普通的數(shù)值然后賦給屬性。

如果指定的key不存在,會給接收者發(fā)送一個setValue:forUndefinedKey:消息。這個方法的默認實現(xiàn)是拋出一個NSUndefinedKeyException異常,子類可以重寫這個方法來自定義默認行為。 方法setValue百科:forKeyPath:的實現(xiàn)跟前面的一樣,只不過它是用來處理鍵路徑的。 setValuesForKeysWithDictionary:方法是用指定字典里的值來賦給接收者相關(guān)的屬性。

這個方法的默認實現(xiàn)是對每一對鍵-值都調(diào)用一次setValue:forKey:方法,并且自動將nil轉(zhuǎn)成NSNull。 **,你要關(guān)心的當嘗試將一個nil值賦給一個非對象類型的時候該怎么辦。這種情況下,接收者會發(fā)出一個setNilValueForKey:消息,這個方法的默認實現(xiàn)是拋出一個NSInvalidArgumentException。

kvc和kvo原理

KVC和KVO想必都熟知的一個名詞,采用觀察者模式,那么KVC到底是個什么,KVO又是什么,它們之間是怎樣關(guān)聯(lián)的,一起來解決這些疑惑。像我們銀行卡bankCard的余額變動,會及時通知給用戶,這種場景就運用了觀察者模式,達到了系統(tǒng)的高效高性能處理;當你了解KVC機制,會恍然大悟,只要知道一個UI的結(jié)構(gòu),就能對他做任意的修改,所以了解KVC和KVO的機制原理還是很重要的。

一、首先先講KVC,KVC簡稱KeyValueCoding,是一個基于NSKeyValueCoding非正式協(xié)議的機制,就是直接通過key值對對象的屬性進行存取操作,而不是通過明確的存取方法,簡而言之也就是一系列規(guī)則和方法進行的存取操作,那接下來深入了解KVC在底層做了些什么。

注:NSObject是定義了KVC的,所以繼承NSObject的對象都支持KVC,基本上所有的OC對象都支持KVC。1、 首先我們了解取值功能,MyObject對象代碼如下: @interface MyObject : NSObject @property (nonatomic, strong)NSString *name; @end123123我們對該對象的name進行取值myObject = [[MyObject alloc] init];myObject.name = @\”八點鐘\”;NSLog(@\”%@\”, myObject.name);123123當執(zhí)行myObject.name時,系統(tǒng)自動會執(zhí)行- (NSString*)name方法,這個方法在property建立的時候,系統(tǒng)會默認生成,也會對應(yīng)的生成setName方法。2、我們換以一種形式來訪問,在沒有主動建立property的情況下,MyObject對象代碼如下:@interface MyObject : NSObject@end1212我們對該對象的name進行取值myObject = [[MyObject alloc] init];NSLog(@\”%@\”,[myObject valueForKey:@\”name”]);1212當執(zhí)行[myObject valueForKey:@”name”]時,我們沒有定義屬性name,系統(tǒng)就會根據(jù)key來進行一個搜索,那么KVC執(zhí)行規(guī)則是:依次搜索-(NSString*)getName方法,- (NSString*)name方法,- (NSString*)isName方法,這三個方法的先后順序來查找,如果有,則執(zhí)行相應(yīng)的方法,(這是按NSString類型的查找規(guī)則)。如果沒有則繼續(xù)找,因為key:@”name”,系統(tǒng)也不知道查找的name是什么類型的,那么系統(tǒng)會按照其他數(shù)據(jù)類型的方式繼續(xù)找,如數(shù)組NSArray查找方式是會找這兩個方法-(NSUInteger)countOfName-(id)objectInNameAtIndex:(NSUInteger)index1212如果找到了就執(zhí)行。

依此類推還有其他數(shù)據(jù)類型的查找方式,不一一例舉出來了,重點是了解有這么一個過程,KVC原理。如果按照KVC規(guī)則沒有查找到相應(yīng)的方法則會調(diào)用valueForUndefinedKey:方法,系統(tǒng)直接拋出異常,程序Crash, 我們可以重寫valueForUndefinedKey這個方法,則不會導(dǎo)致系統(tǒng)拋出異常,防止程序奔潰。那么KVC還提供了valueForKeyPath:等這些取值方法。

注意如果是BOOL或者int等值類型,會做NSNumber轉(zhuǎn)換。講了這么多,來一波代碼,看現(xiàn)象:(依次注釋MyObject類里面的方法來看效果就一目了然,代碼簡單,磨起鍵盤吧,高手是敲出來的,背后都有一部擼的辛酸史,實踐出真知,代碼擼起來)??二、接下來我們來研究存的操作(修改對象屬性)property的上面已經(jīng)提到了,來看另一種方式setValue:forKey或setValue:forKeyPath等方法。對象代碼:(MyObjectTwo類沒有定義任何屬性)@interface MyObjectTwo :NSObject@end1212執(zhí)行代碼myObjectTwo = [[MyObjectTwoalloc]init];[myObjectTwo setValue:@\”八點種學(xué)院\” forKey:@\”name\”];1212調(diào)用setValue:forkey:代碼時,系統(tǒng)沒有自定屬性name,那么底層會怎么做呢, 系統(tǒng)執(zhí)行的操作:系統(tǒng)會去找setName:屬性值方法,如果沒有找到setName:方法,KVC機制會檢查(BOOL)accessInstanceVariablesDirectly方法有沒有返回YES,系統(tǒng)默認是返回YES的,但我們可以重寫該方法,返回NO,如果是返回NO,沒找到setName方法,那么系統(tǒng)就會執(zhí)行setValue:ForUndefineKey:方法,系統(tǒng)拋出異常,程序Crash。

返回YES,繼續(xù)搜索類里面成員變量,搜索順序依次是_name、_isName、name、isName,如果找了相應(yīng)變量,就停止尋找,對該變量進行修改。動起手來,看機制,一切盡在擼??注意:當對NSDictionary對象使用KVC時,valueForKey:和objectForKey:效果一樣。可以看出利用KVC可以修改類的私有變量,可以修改IOS隱藏一些屬性,如UITextField的placeHolderText默認style在需求中達不到要求,我們可以直接通過KVC快速定義自己的style,代碼如下:[textField setValue:[UIColor redColor] forKeyPath:@\”placeholderLabel.textColor\”];11如果你了解一個UI的內(nèi)部結(jié)構(gòu),你可以通過KVC可以改變系統(tǒng)默認的任何效果,KVC是不是很強大。

本文簡單的講述了KVC的內(nèi)部原理,如果一個框架沒有KVC機制的時候,我們就可以簡單實現(xiàn)自己的KVC,一個程序猿追求的應(yīng)該不是對工具的使用,而是理解原理機制,創(chuàng)造工具,那么你就是牛B的。

解釋 KVC 和 KVO

Key value coding, Key value observer. Kvc 是路徑訪問的規(guī)范,kvo 是觀察某個變量的變化過程 KVO 可以觀察某個對象的變量變化過程,KVC 是滿足被觀察的編碼規(guī)范。 KVC/KVO 類似于**,通知中心。

都是一種通訊方法。

iOS-KVC和KVO

重新整理一波KVO和KVC. 整理以前的認識, 在一個類里面創(chuàng)建屬性, 系統(tǒng)會給當前的類創(chuàng)建帶下劃線的成員變量. 所以只要知道了屬性名稱,就可以通過KVC對類的屬性進行賦值 問題 : 1.能不能為類的屬性通過KVC的方式賦值. 2.能不能為類的內(nèi)部成員屬性(implement里面的帶下劃線的匿名成員函數(shù))賦值 打印結(jié)果 KVO的實現(xiàn)原理