http://www.cnblogs.com/dyf520/p/3805297.html

1,什么是Key-Value Coding? Key-Value Coding是一种间接访问对象属性的机制,使用字符串标识属性,而不是通过调用实例变量的访问方法。其使用的方法基本都声明自NSKeyValueCoding协议,并被NSObject实现。

Key-Value Coding支持对象属性,也支持标量类型和结构类型。非对象参数和返回类型被自动包装和解包装。

NSKeyValueCoding定义的方法有:

获得属性值的方法:

– valueForKey:

– valueForKeyPath:

– dictionaryWithValuesForKeys:

– valueForUndefinedKey:

– mutableArrayValueForKey:

– mutableArrayValueForKeyPath:

– mutableSetValueForKey:

– mutableSetValueForKeyPath:

– mutableOrderedSetValueForKey:

– mutableOrderedSetValueForKeyPath:

设置属性值的方法:

– setValue:forKeyPath:

– setValuesForKeysWithDictionary:

– setNilValueForKey:

– setValue:forKey:

– setValue:forUndefinedKey:

更改默认行为的方法:

+ accessInstanceVariablesDirectly

验证方法:

– validateValue:forKey:error:

– validateValue:forKeyPath:error:

2,通过KVC获得属性值:方法valueForKey:返回指定键的值,如果没有这个键,接收者会发送给自己一个valueForUndefinedKey:消息。默认的valueForUndefinedKey:消息会引起一个NSUndefinedKeyException,子类化可以重载该行为。

ValueForKeyPath:也是类似的。

方法dictionaryWithValuesForKeys:检索接收者一组keys的值。

提示:集合对象,如NSArray,NSSet,NSDictionary,不能包含nil值,取而代之的,你使用特定对象,NSNull.NSNull来代替nil值。默认的dictionaryWithValuesForKeys:和setValuesForKeysWithDictionary:方法的实现自动转换NSNull 和nil,所以你的对象不用显式地测试NSNull值。

3,通过KVC设置属性值:方法setValue:forKey:。其默认实现自动解包装表示标量和结构类型的NSValue对象。如果指定键不存在,接收者会发送一个setValue:ForUndefinedKey:消息。该方法的默认实现会抛出一个NSUndefinedKeyException异常;子类化可以重载该行为。

SetValuesForKeysWithDictionary:设置接收者字典中的所有键值的值。默认实现调用每个键值对的setValue:forKey:,并用nil代替NSNull。

4,通用的访问格式: -<key> 方法返回一个对象、标量或者结构。 -is<key>支持布尔类型.

5,通用的设置值的格式为 set<Key>:

如果属性是一个非对象类型,你还必须实现nil值的含义。setNilValueForKey:方法在你尝试设置nil给属性的时候被调用。

如下例所示:

- (void)setNilValueForKey:(NSString *)theKey {

if ([theKey isEqualToString:@"hidden"]) {

[self setValue:@YES forKey:@"hidden"];

}

else {

[super setNilValueForKey:theKey];

}

}

6,通用的集合访问格式: mutableArrayValueForKey: 或mutableSetValueForKey:

7,索引访问格式:-countOf<Key>

-objectIn<Key>AtIndex: 或者 -<key>AtIndexes:

-get<Key>:range:

如下例所示:

Listing 4  Example -count<Key> implementation

- (NSUInteger)countOfEmployees {

return [self.employees count];

}

- (id)objectInEmployeesAtIndex:(NSUInteger)index {

return [employees objectAtIndex:index];

}

- (NSArray *)employeesAtIndexes:(NSIndexSet *)indexes {

return [self.employees objectsAtIndexes:indexes];

}

- (void)getEmployees:(Employee * __unsafe_unretained *)buffer range:(NSRange)inRange {

// Return the objects in the specified range in the provided buffer.

// For example, if the employees were stored in an underlying NSArray

[self.employees getObjects:buffer range:inRange];

}

8,可变索引访问:-insertObject:in<Key>AtIndex: 或者 –insert<Key>atIndexes:

-removeObjectFrom<Key>AtIndex: 或-remove<Key>AtIndexes:

-replaceObjectIn<Key>AtIndex:withObject: 或者 –replace<Key>AtIndexes:with<Key>:

- (void)insertObject:(Employee *)employee inEmployeesAtIndex:(NSUInteger)index {

[self.employees insertObject:employee atIndex:index];

return;

}

- (void)insertEmployees:(NSArray *)employeeArray atIndexes:(NSIndexSet *)indexes {

[self.employees insertObjects:employeeArray atIndexes:indexes];

return;

}

- (void)removeObjectFromEmployeesAtIndex:(NSUInteger)index {

[self.employees removeObjectAtIndex:index];

}

- (void)removeEmployeesAtIndexes:(NSIndexSet *)indexes {

[self.employees removeObjectsAtIndexes:indexes];

}

- (void)replaceObjectInEmployeesAtIndex:(NSUInteger)index

withObject:(id)anObject {

[self.employees replaceObjectAtIndex:index withObject:anObject];

}

- (void)replaceEmployeesAtIndexes:(NSIndexSet *)indexes

withEmployees:(NSArray *)employeeArray {

[self.employees replaceObjectsAtIndexes:indexes withObjects:employeeArray];

}

9,无序访问格式:-countOf<Key>

-enumeratorOf<Key>

-memberOf<Key>:

- (NSUInteger)countOfTransactions {

return [self.transactions count];

}

- (NSEnumerator *)enumeratorOfTransactions {

return [self.transactions objectEnumerator];

}

- (Transaction *)memberOfTransactions:(Transaction *)anObject {

return [self.transactions member:anObject];

}

10,可变无序访问:-add<Key>Object: or -add<Key>:

-remove<Key>Object: or -remove<Key>:

-intersect<Key>:

- (void)addTransactionsObject:(Transaction *)anObject {

[self.transactions addObject:anObject];

}

- (void)addTransactions:(NSSet *)manyObjects {

[self.transactions unionSet:manyObjects];

}

- (void)removeTransactionsObject:(Transaction *)anObject {

[self.transactions removeObject:anObject];

}

- (void)removeTransactions:(NSSet *)manyObjects {

[self.transactions minusSet:manyObjects];

}

- (void)intersectTransactions:(NSSet *)otherObjects {

return [self.transactions intersectSet:otherObjects];

}

11,Key-Value Validation:验证

KVC提供了一致的API来验证属性值。

验证方法:如下所示:

isting 1  Validation method declaration for the property name

-(BOOL)validateName:(id *)ioValue error:(NSError * __autoreleasing *)outError {

// Implementation specific code.

return ...;

}

验证方法有3种可能的输出:

1)对象值是有效的,所以返回YES,不更改值和error

2)对象值无效,并且无法创建一个有效值。这时返回NO,并设置error参数为一个NSError对象表名错误原因。

3)对象值无效,但一个有效值被创建并返回。这时返回YES。并且不设置NSError,但需要设置一个新的ioValue。

-(BOOL)validateName:(id *)ioValue error:(NSError * __autoreleasing *)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 = NSLocalizedString(

@"A Person's name must be at least two characters long",

@"validation: Person, too short name error");

NSDictionary *userInfoDict = @{ NSLocalizedDescriptionKey : errorString };

*outError = [[NSError alloc] initWithDomain:PERSON_ERROR_DOMAIN

code:PERSON_INVALID_NAME_CODE

userInfo:userInfoDict];

}

return NO;

}

return YES;

}

重要提示:一个验证方法如果返回NO,需要首先检查outError参数是否是NULL;如果其不是NULL,方法应该设置outError为一个有效的NSError对象。

12,引入验证方法:你可以直接调用验证方法,通过调用validateValue:forKey:error,并指定一个键。该方法的默认实现搜索接收类名字匹配validate<Key>Error:的验证方法,如果这个方法被找到,他将被调用并返回结果。如果没有找到,返回YES。

警告:-set<Key>的实现方法应该永远不要调用验证方法。

13,自动验证:

一般,KVC不自动执行验证—这是你的责任。

其他一些技术确实执行自动验证:Core Data自动执行验证—当管理的对象的context被保存时;等

14,验证标量值:

-(BOOL)validateAge:(id *)ioValue error:(NSError * __autoreleasing *)outError {

if (*ioValue == nil) {

// Trap this in setNilValueForKey.

// An alternative might be to create new NSNumber with value 0 here.

return YES;

}

if ([*ioValue floatValue] <= 0.0) {

if (outError != NULL) {

NSString *errorString = NSLocalizedStringFromTable(

@"Age must be greater than zero", @"Person",

@"validation: zero age error");

NSDictionary *userInfoDict = @{ NSLocalizedDescriptionKey : errorString };

NSError *error = [[NSError alloc] initWithDomain:PERSON_ERROR_DOMAIN

code:PERSON_INVALID_AGE_CODE

userInfo:userInfoDict];

*outError = error;

}

return NO;

}

else {

return YES;

}

//…

15,确保KVC承诺:

16,如果属性是单一值:

1)实现-<Key> -is<Key>或有实例变量: <key>或_<key>

2)如果属性是可变的,还应该实现-set<Key>

3)-set<key>不应该执行验证。

4)应该实现-validate<Key>:error: 如果验证适合键。

17,索引为多值:

对索引的多值属性:

1)实现 -<key>

2)或者有实例变量 <key>或_<key>

3)或者实现-countOf<key>和-objectIn<Key>AtIndex: 或-<key>AtIndexes:中的一个

4)可选地,你可以实现-get<Key>:range:来提升性能。

对可变的索引有序的多值属性,KVC承诺要求你的类

1)实现 –insertObject:in<Key>AtIndex或-insert<Key>:atIndexes:中的一个

2)实现 –removeObjectFrom<Key>AtIndex: 或 –remove<Key>AtIndexes中的一个。

3)可选地,你可以实现-replaceObjectIn<Key>AtIndex:withObject或-replace<Key>AtIndexes:with<Key>来提升性能。

18,无序多值属性:

对无序多值属性:

1)实现-<key>

2)或有实例变量:<key> or _<key>

3)或实现-countOf<Key>, -enumeratorOf<Key>, and -memberOf<Key>:.

For a mutable unordered to-many relationship, KVC compliance requires that your class also

对可变无序多值属性:

1)实现后面2个方法中的一个: -add<Key>Object: or -add<Key>:.

2)实现后面2个方法中的一个:  -remove<Key>Object: or -remove<Key>:.

3)可选的,你可以实现 -intersect<Key>: and -set<Key>: 来提升性能。

19,标量和结构支持:

默认的实现valueForKey:和setValue:forKey:会自动包装非对象类型,包括标量和结构类型。

一旦valueForKey:已经决定了特定的访问方法或实例变量,它会检查返回类型,如果不是对象,NSNumber和NSValue对象被创建并包装非对象值。

类似的,setValue:forKey 会自动将NSValue或NSNumber对象的xxxValue取出并赋值给属性。

20,处理nil值:setValue:forKey 如果设置nil值给一个非对象属性,接收者发送一个setNilValueForKey消息,默认这会引起一个NSValidArgumentException异常。子类化可以重载该行为。

21,包装和解包装标量值:

22,集合操作符:

keypathToCollection.@collectionOperator.keypathToProperty

所有的集合操作符,除了@count,都要求一个keyPath在操作符的右侧。

1)@avg

2)@count

3)@max:取最大值,如果参与比较的值是nil,则忽略该值。

4)@min:同样忽略nil值

5)@sum:同样忽略nil值

23,对象操作符:

1)@distinctUnionOfObjects:例子:返回

NSArray *payees = [transactions valueForKeyPath:@"@distinctUnionOfObjects.payee"];

2)@unionOfObject:

重要提示:这2个操作符 如果任意的叶对象值为nil,则引起异常。

24,数组和设置操作符:

首先准备数组:

// Create the array that contains additional arrays.

self.arrayOfTransactionsArray = [NSMutableArray array];

// Add the array of objects used in the above examples.

[arrayOfTransactionsArray addObject:transactions];

// Add a second array of objects; this array contains alternate values.

[arrayOfTransactionsArrays addObject:moreTransactions];

1)@distinctUnionOfArrays:返回一个数组,包含distinct对象,如:

NSArray *payees = [arrayOfTransactionsArrays valueForKeyPath:@"@distinctUnionOfArrays.payee"];

2)unionOfArrays:

3)distinctUnionOfSets:

25,访问器搜索实现细节:

26,访问器搜索简单属性的格式:

27,setValue:forKey:的搜索格式:

1)首先查找访问方法 set<Key>:

2) 如果没找到,如果接收者的类方法accessInstanceVariablesDirectly返回YES,接收者搜索实例变量_<key>, is<Key> <key>或is<key>,按照这个顺序查找

3)如果找到了,则使用其来设置值。

4)如果没有找到,调用setValue:forUndfinedKey:

28,valueForKey:的默认搜索格式:

1)按顺序搜索接收者的访问方法 get<Key> <key> 或is<Key>。如果找到,则被调用。

2)否则,搜索接收者的方法countOf<key>、 objectIn<Key>AtIndex: 和 <key>AtIndexes:  如果countOf<Key>方法和至少另外两个可能的方法中找到任意一个,一个集合代理对象响应所有NSArray方法 被返回。

3)否则,超找接收这的countOf<key>、enumeratorOf<key>和memberOf<Key>。如果3个方法都被找到,一个集合代理对象响应所有的NSSet方法 被返回。

4)否则,如果接收者的类方法accessInstanceVariablesDirectly为YES,接收者的类搜索实例变量 _<key> _is<Key> <key> 或 is<key>。找到并返回

5)如果没有找到, valueForUndefinedKey:

29,有序集合的访问器的搜索格式:

mutableArrayValueForKey:的默认搜索格式如下:

1)接收者的类被搜索一对方法 insertObject:in<key>atIndex和removeObjectFrom<key>AtINdex: 或  insert<Key>:atIndexes和 remove<Key>atIndexes:

2)否则,接收者的类搜索 set<Key>:

3)否则,如果接收者的类方法accessInstanceVariablesDirectly为YES,接收者的类搜索实例变量 _<key>  <key> 。找到并返回

4)如果没有找到,调用setValue:forUndfinedKey:

30,唯一有序集合的搜索格式:

mutableOrderedSetValueForKey:

1)搜索方法 insertObject:in<key>atIndex和removeObjectFrom<key>AtINdex: 或  insert<Key>:atIndexes和 remove<Key>atIndexes:

2)否则,接收者的类搜索 set<Key>:

3)否则,如果接收者的类方法accessInstanceVariablesDirectly为YES,接收者的类搜索实例变量 _<key>  <key> 。找到并返回

4)如果没有找到,调用setValue:forUndfinedKey:

31.无序集合的搜索格式:

mytableSetValueForKey:

1)搜索方法 add<key>Object和remove<key>Object: 或  add<Key>和 remove<Key>:

2)否则,接收者的类搜索 set<Key>:

3)否则,如果接收者的类方法accessInstanceVariablesDirectly为YES,接收者的类搜索实例变量 _<key>  <key> 。找到并返回

4)如果没有找到,调用setValue:forUndfinedKey:

 
 
 
 
 
 

键值编码 KVC的更多相关文章

  1. ios中键值编码kvc和键值监听kvo的特性及详解

    总结: kvc键值编码  1.就是在oc中可以对属性进行动态读写(以往都是自己赋值属性)           2. 如果方法属性的关键字和需要数据中的关键字相同的话                  ...

  2. [原创]obj-c编程16:键值编码(KVC)

    原文链接:obj-c编程16:键值编码(KVC) 我们可以借助obj-c中的键值编码(以后简称KVC,Key-Value Coding)来存取类的属性,通过指定所要访问的属性名字符串标示符,可以使用存 ...

  3. iOS监听模式系列之键值编码KVC、键值监听KVO的简单介绍和应用

    键值编码KVC 我们知道在C#中可以通过反射读写一个对象的属性,有时候这种方式特别方便,因为你可以利用字符串的方式去动态控制一个对象.其实由于ObjC的语言特性,你根部不必进行任何操作就可以进行属性的 ...

  4. obj-c编程16:键值编码(KVC)

    我们可以借助obj-c中的键值编码(以后简称KVC,Key-Value Coding)来存取类的属性,通过指定所要访问的属性名字符串标示符,可以使用存取器方法来获取或设置类的属性.下面的例子,借助于K ...

  5. 键值编码KVC

    动态设置:setValue:属性值 forKey:属性名用于简单路径:setValue:属性值 forKeyPath:属性路径用于复合路径,例如Person有一个Account类型的属性,那么pers ...

  6. 路径(keyPath)、键值编码(KVC)和键值观察(KVO)

    键路径 在一个给定的实体中,同一个属性的所有值具有相同的数据类型. 键-值编码技术用于进行这样的查找—它是一种间接访问对象属性的机制. - 键路径是一个由用点作分隔符的键组成的字符串,用于指定一个连接 ...

  7. Objective-C(十七、KVC键值编码及实例说明)——iOS开发基础

    结合之前的学习笔记以及參考<Objective-C编程全解(第三版)>,对Objective-C知识点进行梳理总结.知识点一直在变,仅仅是作为參考,以苹果官方文档为准~ 十七.键值编码 K ...

  8. 09 (OC)* 键路径(keyPath)、键值编码(KVC)、键值观察(KVO)

    键路径在一个给定的实体中,同一个属性的所有值具有相同的数据类型.键-值编码技术用于进行这样的查找—它是一种间接访问对象属性的机制. - 键路径是一个由用点作分隔符的键组成的字符串,用于指定一个连接在一 ...

  9. kvc(键-值编码)

    kvc(键-值编码) { NSString *_name; Author *_author; NSArray *_kvcArray; float price;} //kvc,setValue 的设的值 ...

随机推荐

  1. jQuery的ajax,当async为false时,同步操作失败。解决方式

    引发失败时代码: $.ajax({ url : 'your url', data:{name:value}, cache : false, async : true, type : "POS ...

  2. 仿htc sense的弹性listView!

    demo下载:http://pan.baidu.com/s/1ntoICdV 前一段时间换了htc m7之后,对htc的sense ui有不错的印象.特别是它的listview十分有个性.提供弹性的o ...

  3. Mac中Maven的安装步骤

    1.下载Maven,并解压到某个目录. 2.打开terminal,输入一下命令. open .bash_profile; 3.在bash_profile中,编辑文件  内容如下. 4.保存bash_p ...

  4. ios如何获取手机的网络状态和运营商名称

    本文转载至 http://blog.csdn.net/justinjing0612/article/details/38313747 以前获取手机的网络状态和运营商名称都是似有API, 现在我们可以大 ...

  5. 1507: [NOI2003]Editor

    1507: [NOI2003]Editor Time Limit: 5 Sec  Memory Limit: 162 MB Submit: 3535  Solved: 1435 [Submit][St ...

  6. 阿里巴巴Java开发手册(开发规范)——编程规约笔记

    2.常量规约 [推荐]如果变量值仅在一个范围内变化用Enum类. 如果还带有名称之外的延伸属性,必须使用Enum类, 下面正例中的数字就是延伸信息,表示星期几. 正例: public Enum{ MO ...

  7. archlinux yaourt安装 以及出错细节 database file for "archlinuxfr" does not exist.

    archlinux yaourt安装 但一直报错如下: :: Synchronizing package databases...      core is up to date extra is u ...

  8. dedecms列表页如何调用栏目关键词和描述

    问:dedecms列表页如何调用栏目关键词和描述 答:有人问起dedecms列表页如何调用栏目关键词和描述.解答如下: 自己实验了下总结方法如下:(以下方法使用于栏目封面和列表和内容页,其他的地方没有 ...

  9. Navicat——如何导出所有的查询数据

    前言 很简单就是通过Navicat的查询来查询~ 步骤 真的不要太简单了~ 打开Navicat并点击查询 新建查询 选择对应的连接和库 写入SQL并运行 导出结果 1.选择导出当前的结果 2.选择保存 ...

  10. Fabric原理剖析

    Fabric架构   image.png Fabric网络   image.png Fabric模块   image.png Fabric交易流 根据Hyperledger Fabric 1.0架构, ...