浅谈KVC

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/szk972092933/article/details/78535960

    看了一遍官方文档关于kvc的介绍,总结一下,如有不对之处,请各位朋友能够指正,万分感谢。原文地址https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding

kvc是NSKeyValueCoding非正式协议(Category)所提供的用来一种用来间接读取设置属性(基于get和set方法)的机制。

kvc也是许多Cocoa技术的基础,例如kvo,Cocoa bindings,Core Data和AppleScript-ability等等。

因为NSObject类遵守并实现了NSKeyValueCoding协议的必要方法,所以任何NSObject的子类都可以使用kvc机制。那么kvc都可以用来做什么呢?

一.用来获取对象属性,NSKeyValueCoding协议中 定义了valueForKey和setValue:forKey:方法用来通过property名称读取。property又可分为三类:1.Attribute 代表简单的值例如标量,字符串,bool值,NSNumber和其他不可变类型例如NSColor都属于attributes。2.To-one relationships 代表有自己property的可变对象,例如银行账户对象BankAccount有可能有一个property Person对象owner,而owner可以有自己的property.(owner的property可以改变而不会影响BankAccount对ower的引用)3.To-many relationShips 代表集合对象,例如NSArray 或者 NSSet

举例:

@interface BankAccount : NSObject
@property ( nonatomic ) NSNumber * currentBalance ; // An attribute
@property ( nonatomic ) Person * owner ; // A to-one relation
@property ( nonatomic ) NSArray < Transaction * >* transactions ; // A to-many relation

@end

@interface Person :NSObject
@property(nonatomic)Address*address;// A to-one relation
@end

@interface Address :NSObject
@property(nonatomic)NSString*street;// A to-one relation
@end

所谓的Key即是property的名称字符串 例如我们通过kvc机制来设置currentBalance的值

[myAccountsetValue:@(100.0)forKey:@"currentBalance" ];
key path 就是由点语法所访问的属性 例如 owner.address.street
[myAccount setValue:@"唐人街" forKeyPath:@"owner.address.street"];
使用kvc来读取属性值的三种方法
valueForKey:如果找不到使用这个key作为属性名的属性的值就会调用valueForUndefinedKey:方法,并抛出NSUndefineKeyException异常,子类可以重写这个方法以避免系统默认的抛出异常。
valueForKeyPath:用来通过keyPath来读取属性的值。
dictionaryWithValuesForKeys: 传入 key的数组 返回属性和属性值所组成的字典。
同样对应于三个设置属性值的方法
setValue:froKey:
setValue:forKeyPath:
setValuesForKeysWithDictionary: 其中字典里的每个key对应于对象属性的名称
二、用于获取可变的集合对象
尽管可以使用setValue:forkKeyvalueForKey:来设置和读取一个集合对象,但是如果想获取可变集合要使用如下方法:
mutableArrayValueForKey:  and  mutableArrayValueForKeyPath: 返回一个类似于NSMutableArray的代理对象
mutableSetValueForKey: and mutableSetValueForKeyPath:返回一个类似于NSMutalbeSet的代理对象 mutableOrderedSetValueForKey:  and  mutableOrderedSetValueForKeyPath:返回一个类似于NSMutableOrderedSet对象
三、用于集合属性的运算 包含三种基本的集合运算
1.聚合运算 NSNumber * transactionAverage = [ self . transactions valueForKeyPath: @"@avg.amount" ]; @avg求平均值
@count NSNumber * numberOfTransactions = [ self . transactions valueForKeyPath: @"@count" ];
NSDate * latestDate = [ self . transactions valueForKeyPath: @"@max.date" ];
NSDate * earliestDate = [ self . transactions valueForKeyPath: @"@min.date" ];
2.数组运算
NSArray * distinctPayees = [ self . transactions valueForKeyPath: @"@distinctUnionOfObjects.payee" ];去掉重复元素
NSArray * payees = [ self . transactions valueForKeyPath: @"@unionOfObjects.payee" ];不去掉重复元素
3.嵌套运算
NSArray * moreTransactions = @ [ < # transaction data # > ];
NSArray * arrayOfArrays = @ [ self . transactions , moreTransactions ];
NSArray*collectedDistinctPayees=[arrayOfArraysvalueForKeyPath:@"@distinctUnionOfArrays.payee"];
NSArray * collectedPayees = [ arrayOfArrays valueForKeyPath: @"@unionOfArrays.payee" ];
四.获取非对象的属性
对于非对象的属性例如一个标量或者结构体,当你调用valueForKey:的时候 默认会自动将其转换为nsnumber或者nsvalue对象 typedef struct { float x , y , z ; } ThreeFloats ; @interface MyClass @property ( nonatomic ) ThreeFloats threeFloats ; @end
    1. ThreeFloats floats={1.,2.,3.};
    2. NSValue*value=[NSValue valueWithBytes:&floats objCType:@encode(ThreeFloats)];
    3. [myClass setValue:value forKey:@"threeFloats"];
    4. NSValue*result=[myClass valueForKey:@"threeFloats"];
五、校验属性 Person * person = [[ Person alloc ] init ]; NSError * error ; NSString * name = @"John" ; if ( ! [ person validateValue: & name forKey: @"name" error: & error ]) { NSLog ( @"%@" , error ); } 需自己实现 validateValue:forKey方法来校验属性值是否正确。 六、访问器查找模式 基本属性的调用valueForKey:查找模式 1.首先查找对象实例方法如:get<Key>, <key>, is<Key> 或者_<key>如果找到了就调用然后执行步骤5,如果没找到继续执行步骤2 2.如果没有找到通用的读取器方法,那么就会查找实例方法:countOf<Key> 和objectIn<Key>AtIndex:(与nsarray类的原始方法类似) 和<key>AtIndexes:(对应NSArray的objectsAtIndexes:方法),如果第一个方法和另外两个方法中的一个被查找到了,那么就会创建一个能够响应所有NSArray方法的代理集合对象并返回。这个代理对象随后将所有对他调用数组对象的方法分解为countOf<Key>,ObjectIn<Key>AtIndex和<key>AtIndexs:方法的组合。实际上这个代理对象会表现的像数组一样,即使它不是一个NSArray对象。 3.如果既没有找到通用的存取访问方法,或者像数组一样的读取方法,那么就会查找第三类方法countOf<Key>,enumeratorOf<Key>和memberOf<Key>(对应NSSet的私有方法)。如果这三个方法都找到了,那么就会创建一个类似于NSSet的代理对象并返回。同样它会将调用的NSSet方法,分解为调用这三个方法的组合来实现。 4.如果以上方法都没有查找到,并且这个对象的类方法 accessInstanceVariablesDirectly 返回YES,那么会按顺序查找_<key>,_is<Key>,<key>,或者is<Key> 5.如果找到的属性值是一个对象指针,那么就返回这个结果,如果是被NSNumber支持的标量类型,那么就将他存到NSNumber实例,并返回,如果不被NSNumber支持,那么就将他装换为NSValue对象并返回。 6.如果上述所有方法都没有找到,那么就会调用valueForUndefinedKey:.这个方法默认抛出一个异常,但是NSObject的子类可以根据不同的key来处理。 基本类型的Setter方法的搜索模式 1.首先按顺序查找set<Key>: or _set<Key>,如果找到那么久调用它。 2.如果没有找到到,并且这个对象的类方法 accessInstanceVariablesDirectly 返回了YES,那么就会查找实例变量名称为_<key>,_is<Key>,<key>或者is<Key>,如果找到那么就直接赋值()。 3.如果都没找到,直接调用setValue:forUndefinedKey,这个方法会抛出异常。 对于可变数组的查找模式(mutalbeArrayValueForKey:) 1.查找一对插入删除方法 insertObject:in<Key>AtIndex:和removeObjectFrom<Key>AtIndex:(对应于NSMutalbeArray的原始方法insertObject:atIndex: 和 removeObjectAtIndex:)或者insert<Key>:atIndexes: and remove<Key>AtIndexes: 如果找到其中任意一对插入删除方法,那么就会返回一个类似于NSMutalbeArray的代理对象,对于任何调用NSMutableArray的方法,它都会调用二者的组合来实现。 2.如果这个对象没有事项可变数组的方法,那么就会查找存取器方法set<Key>: (会创建新的可变数组对象,不如实现第一条中的方法效率高) 3.如果以上方法都没有查找到,并且 accessInstanceVariablesDirectly 方法返回YES,那么会查找实例变量_<key>或者<key> 4.如果都没有找到,返回的对象在调用NSMutableArray方法时 会调用setValue:forUndeinedKey 可变有序集合的查找模式( mutableOrderedSetValueForKey: 1.查找 insertObject:in<Key>AtIndex:  and  removeObjectFrom<Key>AtIndex:  或者insert<Key>:atIndexes: and remove<Key>AtIndexes:方法 如果找到返回的对象在调用NSMutableOrderedSet方法的时候也可能会调用 replaceObjectIn<Key>AtIndex:withObject:  or  replace<Key>AtIndexes:with<Key>:方法。
    1. 2.如果这个对象没有事项可变数组的方法,那么就会查找存取器方法set<Key>: (会创建新的可变数组对象,不如实现第一条中的方法效率高)
    2. 3.如果以上方法都没有查找到,并且accessInstanceVariablesDirectly方法返回YES,那么会查找实例变量_<key>或者<key>
    3. 4.如果都没有找到,返回的对象在调用NSMutableOrderedSet方法时 会调用setValue:forUndeinedKey
可变集合( mutableSetValueForKey: 1.查找 add<Key>Object:  and  remove<Key>Object:或者add<Key>: and remove<Key>:方法,如果有一个添加方法和一个删除方法被找到,那么会返回一个代理对象,对于调用NSMutableSet的方法 也会用到 intersect<Key>:  or  set<Key>: 2.如果调用mutableSetValueForKey:的对象是一个managed对象,那么会停止否则继续下一步详情见   Core Data Programming Guide 3.如果一中的方法没有找到,并且对象不是一个托管对象,那么会查找set<Key>: 3.如果以上方法都没有查找到,并且 accessInstanceVariablesDirectly 方法返回YES,那么会查找实例变量_<key>或者<key> 4.如果都没有找到,返回的对象在调用NSMutableSet方法时 会调用setValue:forUndeinedKey









猜你喜欢

转载自blog.csdn.net/szk972092933/article/details/78535960
KVC