1. 程式人生 > >Objective-C KVC機制

Objective-C KVC機制

1.    基本概念

MODEL

主要是英文文件裡面經常出現的一些概念,講解一下,方便英文文件的閱讀。

IOS應用開發是遵循MVC設計模式的,Cocoa框架用Object Modeling的規則來規範一個Model的實現。

ObjectModeling有如下幾個概念的規定:

Entity:表示持有資料的一個實體

Property實體中的成員,分為Attribute和:Relationship

Attribute:基本型別的成員,比如:數字、NSString。

Relationship:指向其它Entity的關係型成員,它又有to 1Relationship和to manyRelationship的區別。

AccessorMethod:getter,setter。

舉例:

如下是一個部門和員工關係的Model

部門:Department

部門名稱(NSString)

成員(NSArray)

部長(Employee)

MIC

(所有成員)

老王(一個成員)

MIB

員工:Employee

名字(NSStirng)

所屬部門(Department)

小王

MIC

使用KVC、KVO的優勢

通過規定了一組通用的Cocoa命名法則、呼叫規則等,實現瞭如下功能: 

²  使用一對高度規範化的訪問方法,獲取以及設定任何物件的任何屬性的值。

²  通過繼承一個特定的方法,並且指定希望監視的物件及希望監視的屬性名稱,就能在該物件的指定屬性的值發生改變時,得到一個“通知”(儘管這不是一個真正意 義上的通知),並且得到相關屬性的值的變化(原先的值和改變後的新值)。

²  通過一個簡單的函式呼叫,使一個檢視物件的一個指定屬性隨時隨地都和一個控制器物件或模型物件的一個指定屬性保持同步。

2.    KVC

2.1  概述

KVC是KeyValue Coding的簡稱,它是一種可以直接通過字串的名字(key)來訪問類屬性的機制。而不是通過呼叫Setter、Getter方法訪問。

當使用KVO、Core Data、CocoaBindings、AppleScript(Mac支援)時,KVC是關鍵技術。

2.2  如何使用KVC

關鍵方法定義在:NSKeyValueCodingprotocol

KVC支援類物件和內建基本資料型別。

2.2.1         獲取值

valueForKey:,傳入NSString屬性的名字。

valueForKeyPath:,傳入NSString屬性的路徑,xx.xx形式。

valueForUndefinedKey它的預設實現是丟擲異常,可以重寫這個函式做錯誤處理。

2.2.2         修改值

setValue:forKey:

setValue:forKeyPath:

setValue:forUndefinedKey:

setNilValueForKey: 當對非類物件屬性設定nil時,呼叫,預設丟擲異常。

2.2.3         一對多關係成員的情況

mutableArrayValueForKey:有序一對多關係成員  NSArray

mutableSetValueForKey:無序一對多關係成員  NSSet

示例:

2.3  KVC的實現細節

搜尋Setter、Getter方法

 這一部分比較重要,能讓你瞭解到KVC呼叫之後,到底是怎樣獲取和設定類成員值的。

2.3.1         搜尋簡單的成員

如:基本型別成員,單個物件型別成員:NSInteger,NSString*成員。

a. setValue:forKey的搜尋方式:

1. 首先搜尋set<Key>:方法

如果成員用@property,@synthsize處理,因為@synthsize告訴編譯器自動生成set<Key>:格式的setter方法,所以這種情況下會直接搜尋到。

注意:這裡的<Key>是指成員名,而且首字母大寫。下同。

2. 上面的setter方法沒有找到,如果類方法accessInstanceVariablesDirectly返回YES(注:這是NSKeyValueCodingCatogery中實現的類方法,預設實現為返回YES)。

那麼按_<key>,_is<Key>,<key>,is<key>的順序搜尋成員名。

3. 如果找到設定成員的值,如果沒有呼叫setValue:forUndefinedKey:。

b. valueForKey:的搜尋方式:

1. 首先按get<Key>、<key>、is<Key>的順序查詢getter方法,找到直接呼叫。如果是bool、int等內建值型別,會做NSNumber的轉換。

2. 上面的getter沒有找到,查詢countOf<Key>、objectIn<Key>AtIndex:、<Key>AtIndexes格式的方法。

如果countOf<Key>和另外兩個方法中的一個找到,那麼就會返回一個可以響應NSArray所有方法的代理集合(collection proxy object)。傳送給這個代理集合(collection proxy object)的NSArray訊息方法,就會以countOf<Key>、objectIn<Key>AtIndex:、<Key>AtIndexes這幾個方法組合的形式呼叫。還有一個可選的get<Key>:range:方法。

3. 還沒查到,那麼查詢countOf<Key>、enumeratorOf<Key>、memberOf<Key>:格式的方法。

如果這三個方法都找到,那麼就返回一個可以響應NSSet所有方法的代理集合(collection proxy object)。傳送給這個代理集合(collection proxy object)的NSSet訊息方法,就會以countOf<Key>、enumeratorOf<Key>、memberOf<Key>:組合的形式呼叫。

4. 還是沒查到,那麼如果類方法accessInstanceVariablesDirectly返回YES,那麼按_<key>,_is<Key>,<key>,is<key>的順序直接搜尋成員名。

5. 再沒查到,呼叫valueForUndefinedKey:。

2.3.2         查詢有序集合成員,比如NSMutableArray

mutableArrayValueForKey:搜尋方式如下:

1. 搜尋insertObject:in<Key>AtIndex:、removeObjectFrom<Key>AtIndex:或者insert<Key>:atIndexes、remove<Key>AtIndexes:格式的方法。

如果至少一個insert方法和至少一個remove方法找到,那麼同樣返回一個可以響應NSMutableArray所有方法的代理集合。那麼傳送給這個代理集合的NSMutableArray訊息方法,以insertObject:in<Key>AtIndex:、removeObjectFrom<Key>AtIndex:、insert<Key>:atIndexes、remove<Key>AtIndexes:組合的形式呼叫。還有兩個可選實現的介面:replaceObjectIn<Key>AtIndex:withObject:、replace<Key>AtIndexes:with<Key>:。

2. 否則,搜尋set<Key>:格式的方法,如果找到,那麼傳送給代理集合的NSMutableArray最終都會呼叫set<Key>:方法。

也就是說,mutableArrayValueForKey取出的代理集合修改後,用set<Key>:重新賦值回去。這樣做效率會差很多,所以推薦實現上面的方法。

3. 否則,那麼如果類方法accessInstanceVariablesDirectly返回YES,那麼按_<key>,<key>的順序直接搜尋成員名。如果找到,那麼傳送的NSMutableArray訊息方法直接轉交給這個成員處理。

4. 再找不到,呼叫setValue:forUndefinedKey:。

2.3.3         搜尋無序集合成員,如:NSSet。

mutableSetValueForKey:搜尋方式如下:

1. 搜尋add<Key>Object:、remove<Key>Object:或者add<Key>:、remove<Key>:格式的方法,如果至少一個insert方法和至少一個remove方法找到,那麼返回一個可以響應NSMutableSet所有方法的代理集合。那麼傳送給這個代理集合的NSMutableSet訊息方法,以add<Key>Object:、remove<Key>Object:、add<Key>:、remove<Key>:組合的形式呼叫。還有兩個可選實現的介面:intersect<Key>、set<Key>:。

2. 如果reciever是ManagedObejct,那麼就不會繼續搜尋了。

3. 否則,搜尋set<Key>:格式的方法,如果找到,那麼傳送給代理集合的NSMutableSet最終都會呼叫set<Key>:方法。也就是說,mutableSetValueForKey取出的代理集合修改後,用set<Key>:重新賦值回去。這樣做效率會差很多,所以推薦實現上面的方法。

4. 否則,那麼如果類方法accessInstanceVariablesDirectly返回YES,那麼按_<key>,<key>的順序直接搜尋成員名。如果找到,那麼傳送的NSMutableSet訊息方法直接轉交給這個成員處理。

5. 再找不到,呼叫setValue:forUndefinedKey:。

KVC還提供了下面的功能

2.4  值的正確性核查

KVC提供屬性值確認的API,它可以用來檢查set的值是否正確、為不正確的值做一個替換值或者拒絕設定新值並返回錯誤原因。

實現核查方法

為如下格式:validate<Key>:error:

如:

-(BOOL)validateName:(id *)ioValue error:(NSError **)outError
{
    // The name must not be nil, and must be at least two characters long.
    if ((*ioValue == nil) || ([(NSString *)*ioValue length] < 2]) {
        if (outError != NULL) {
            NSString *errorString = NSLocalizedStringFromTable(
                    @"A Person's name must be at least two characters long", @"Person",
                    @"validation: too short name error");
            NSDictionary *userInfoDict =
                [NSDictionary dictionaryWithObject:errorString
                                            forKey:NSLocalizedDescriptionKey];
            *outError = [[[NSError alloc] initWithDomain:PERSON_ERROR_DOMAIN
                                                    code:PERSON_INVALID_NAME_CODE
                                                userInfo:userInfoDict] autorelease];
        }
        return NO;
    }
    return YES;
}


呼叫核查方法: 

validateValue:forKey:error:,預設實現會搜尋 validate<Key>:error:格式的核查方法,找到則呼叫,未找到預設返回YES。

注意其中的記憶體管理問題。

2.5  集合操作

集合操作通過對valueForKeyPath:傳遞引數來使用,一定要用在集合(如:array)上,否則產生執行時刻錯誤。其格式如下:

Left keypath部分:需要操作物件路徑。

Collectionoperator部分:通過@符號確定使用的集合操作。

Rightkey path部分:需要進行集合操作的屬性。

2.5.1         資料操作

@avg:平均值

@count:總數

@max:最大

@min:最小

@sum:總數

確保操作的屬性為數字型別,否則執行時刻錯誤。

2.5.2         物件操作

針對陣列的情況

@distinctUnionOfObjects:返回指定屬性去重後的值的陣列

@unionOfObjects:返回指定屬性的值的陣列,不去重

屬性的值不能為空,否則產生異常。

2.5.3         陣列操作

針對陣列的陣列情況

@distinctUnionOfArrays:返回指定屬性去重後的值的陣列

@unionOfArrays:返回指定屬性的值的陣列,不去重

@distinctUnionOfSets:同上,只是返回值為NSSet

示例程式碼:

2.6  效率問題

相比直接訪問KVC的效率會稍低一點,所以只有當你非常需要它提供的可擴充套件性時才使用它。


相關推薦

Objective-C KVC機制

1.    基本概念 MODEL 主要是英文文件裡面經常出現的一些概念,講解一下,方便英文文件的閱讀。 IOS應用開發是遵循MVC設計模式的,Cocoa框架用Object Modeling的規則來規範一個Model的實現。 ObjectModeling有如下幾個概念的規定:

Objective-C runtime機制

Objective-C runtime機制 先來看看怎麼理解發送訊息的含義: 曾經覺得Objc特別方便上手,面對著 Cocoa 中大量 API,只知道簡單的查文件和呼叫。還記得初學 Objective-C 時把[receiver message]當成簡單的方法呼叫,而無視了“傳送訊息

Objective-C runtime機制(7)——SideTables, SideTable, weak_table, weak_entry_t

在runtime中,有四個資料結構非常重要,分別是SideTables,SideTable,weak_table_t和weak_entry_t。它們和物件的引用計數,以及weak引用相關。 關係 先說一下這四個資料結構的關係。 在runtime記憶體空間中,SideTables是

Objective-C runtime機制(6)——weak引用的底層實現原理

前言 提起弱引用,大家都知道它的作用: (1)不會新增引用計數 (2)當所引用的物件釋放後,引用者的指標自動置為nil 那麼,圍繞它背後的實現,是怎麼樣的呢?在許多公司面試時,都會問到這個問題。那麼,今天就帶大家一起分析一下weak引用是怎麼實現的,希望能夠搞清楚每一個細節。 S

Objective-C runtime機制(5)——iOS 記憶體管理

概述 當我們建立一個物件時: SWHunter *hunter = [[SWHunter alloc] init]; 上面這行程式碼在棧上建立了hunter指標,並在堆上建立了一個SWHunter物件。目前,iOS並不支援在棧上建立物件。 iOS 記憶體分割槽 iOS

Objective-C runtime機制(4)——深入理解Category

在平日程式設計中或閱讀第三方程式碼時,category可以說是無處不在。category也可以說是OC作為一門動態語言的一大特色。category為我們動態擴充套件類的功能提供了可能,或者我們也可以把一個龐大的類進行功能分解,按照category進行組織。 關於category的使用

Objective-C runtime機制(3)——method swizzling

方法替換,又稱為method swizzling,是一個比較著名的runtime黑魔法。網上有很多的實現,我們這裡直接講最正規的實現方式以及其背後的原理。 Method Swizzling 在進行方法替換前,我們要考慮兩種情況: 要替換的方法在target class

Objective-C runtime機制(2)——訊息機制

當我們用中括號[]呼叫OC函式的時候,實際上會進入訊息傳送和訊息轉發流程: 訊息傳送(Messaging),runtime系統會根據SEL查詢對用的IMP,查詢到,則呼叫函式指標進行方法呼叫;若查詢不到,則進入訊息轉發流程,如果訊息轉發失敗,則程式crash並記錄日誌。

Objective-C runtime機制(1)——基本資料結構:objc_object & objc_class

前言 從本篇文章開始,就進入runtime的正篇。 什麼是runtime? OC是一門動態語言,與C++這種靜態語言不同,靜態語言的各種資料結構在編譯期已經決定了,不能夠被修改。而動態語言卻可以使我們在程式執行期,動態的修改一個類的結構,如修改方法實現,繫結例項變數等。

Objective-C runtime機制(前傳2)——Mach-O格式和runtime

在前傳1中,我們分析瞭解了XNU核心所支援的二進位制檔案格式Mach-O。同時還留了一個小尾巴,就是Mach-O檔案中和Objective-C以及runtime相關的Segment section。今天,就來了解一下它們。 OC之源起 我們知道,程式的入口點在iOS中被稱之為ma

Objective-C runtime機制(前傳)——Mach-O格式

Mach-O Mach-O是Mach Object檔案格式的縮寫。它是用於可執行檔案,動態庫,目的碼的檔案格式。作為a.out格式的替代,Mach-O格式提供了更強的擴充套件性,以及更快的符號表資訊訪問速度。 Mach-O格式為大部分基於Mach核心的作業系統所使用的,包括NeX

iOS 開發--Objective-C 反射機制

瞭解反射機制 Objective-C語言中的OC物件,都繼承自NSObject類。這個類為我們提供了一些基礎的方法和協議,我們可以直接呼叫從這個類繼承過來方法。當然,本篇文章中講到的反射方法,就在NSObject和Foundation框架中。 反射機制涉及到的東西比較

Objective-C內存管理機制

析構函數 tomat 機制 如果 ngs 都是 範圍 管理 c內存 Objective-C內存管理機制分成兩種:MRC和ARC (1)MRC (Manual Reference Counting) 當前系統默認都是采用ARC,如果想使用MRC需要在build settin

Objective-C中的記憶體管理機制

從蘋果的官方文件來看,OC對應用程式的記憶體管理提供了2種方法。 第一種即“manual retain-release”(MRR),手動保留釋放,也可理解為手動引用計數。 第二種,“Automatic Reference Counting”(ARC),自動引用計數。但是ARC並不等同垃圾回收。在蘋果的官方

objective-c程式碼轉c++程式碼,瞭解底層實現機制

1、開啟終端,輸入    clang -rewrite-objc main.m   2、有時會遇到找不到系統庫的標頭檔案,如   解決辦法:   指定模擬器: xcrun -sdk iphonesimulator

ios學習路線—Objective-C(Runtime訊息機制)

RunTime簡稱執行時。就是系統在執行的時候的一些機制,其中最主要的是訊息機制。對於C語言,函式的呼叫在編譯的時候會決定呼叫哪個函式( C語言的函式呼叫請看這裡 )。編譯完成之後直接順序執行,無任何二義性。OC的函式呼叫成為訊息傳送。屬於動態呼叫過程。在編譯的時候並不能決定真正呼叫哪個函式(事實證明,在編

Objective-C回撥機制(delegate, protocol)

轉載:http://blog.sina.com.cn/s/blog_6545eb460100pyjy.html Objective-C是隻支援單一繼承的,當需要建立一個類能表現多個類的特性時,需要採用與Java中很類似的稱為協議(Protocol)的方法。如同一個類a,一個

Objective-C Runtime 總結:訊息機制

Objective-C語言是一門動態語言,它將很多靜態語言在編譯和連結時期做的事放到了執行時來處理。這種動態語言的優勢在於:我們寫程式碼時更具靈活性,如我們可以把訊息轉發給我們想要的物件,或者隨意交換一個方法的實現等。 與Runtime互動 Objc 從

Objective-C與Runtime的那點事兒訊息機制

最近在找工作,Objective-C中的Runtime是經常被問到的一個問題,幾乎是面試大公司必問的一個問題。當然還有一些其他問題也幾乎必問,例 如:RunLoop,Block,記憶體管理等。其他的問題如果有機會我會在其他文章中介紹。本篇文章主要介紹RunTime。 R

objective-c中的訊息響應機制

        學習objective-c必然會接觸訊息操作,下面就訊息的響應過程做一下分析和總結。         首先我們需要了解oc中的3種物件:例項物件;類物件;元類物件。 例項物件中儲存著的主要結構有:isa指標,指向其類物件;例項成員變數;還有count引用計數