主业iOS/PHP,副业啥都玩,QQ:705719110,欢迎来撩!

iOS中的键值编码(KVC)与观察(KVO)(二)

iOS开发 随风 120℃ 0评论

KVC和非对象

valueForKey: 总是返回一个 id 对象,非对象返回值会用 NSValue 或者 NSNumber 封装,尽管会自动封装对象,却不能把非对象传给 setValue: forKey: ,必须用NSValue 或者 NSNumber分装标量。
把非对象属相设为 nil 是一种特殊情况,这种操作是否合法取决于具体情况,所以KVC不错猜测,如果我们要用 nil 值作为参数来调用 setValue : forKey: ,那么键就会被传递给setNilValueForKey: ,那就需要覆盖这个方法并作出正确的操作,因为系统默认的行为是抛出异常。

KVC的消息传递机制

valueForKey:的使用并不仅仅用来取值那么简单,还有很多特殊的用法,集合类也覆盖了这个方法,通过调用valueForKey:给容器中的每一个对象发送操作消息,并且结果会被保存在一个新的容器中返回,这样我们能很方便的利用一个容器对象创建另一个容器对象。另外,valueForKeyPath:还能实现多个消息的传递。

KVC容器操作

容器不仅仅能使用KVC方法实现对容器成员传递普通的操作消息,KVC还定义了特殊的一些常用操作,使用valueForKeyPath:结合操作符来使用,所定义的keyPath格式入下图所示

kvc:kvo001

Left key path:如果有,则代表需要操作的对象路径(相对于调用者)
Collection operator:以”@”开头的操作符
Right key path:指定被操作的属性

常规操作符:
@avg、@count、@max、@min、@sum

对象操作符:
@distinctUnionOfObjects、@unionOfObjects

@distinctUnionOfObjects操作符返回被操作对象指定属性的集合并做去重操作,而@unionOfObjects则允许重复。如果其中任何涉及的对象为nil,则抛出异常。

Array和Set操作符:
Array和Set操作符操作对象是嵌套型的集合对象
@distinctUnionOfArrays、@unionOfArrays

同样的,返回被操作集合下的集合中的对象的指定属性的集合,并且做去重操作,而@unionOfObjects则允许重复。如果其中任何涉及的对象为nil,则抛出异常。

@distinctUnionOfSets

返回结果同理于NSArray。
据官方文档说明,目前还不支持自动以操作符。

KVC与容器类(集合代理对象)

当然对象的属性可以是一对一的,也可以是一对多。属性的一对多关系其实就是一种对容器类的映射。如果有一个名为numbers的数组属性,我们可以使用valueForKey:@”numbers”来获取,这个是没问题的,但KVC还能使用更灵活的方式管理集合。——集合代理对象

就算没有numbers 这个属性,KVC系统也能创建一个行为跟数组一样的代理对象。原因是 TwoTimesArray 实现了 countOfNumbers 和 objectInNumbersAtIndex: 方法,这些方法是特殊命名过的。当 valueForKey: 寻找对应项时,会搜索如下方法:

1、getNumbers、numbers 或者isNumbers 系统会按照顺序搜索这些方法,第一个找到的方法用来返回请求的值。
2、countOfNumbers、objectInNumbersAtIndex: 或 numbersAtIndexes 这是本例用到的组合。KVO会生成一个代理数组。
3、countOfNumbers、enumeratorOfNumbers 或者 memberOfNumbers 这个组合会让KVC返回一个代理集合。
4、命名为 _numbers、_isNumbers、numbers 或者 isNumber 的实例变量,KVC会直接访问 ivar ,一般最好避免这种行为,直接访问实例变量破坏了封装原则,使代码更脆弱,通过覆盖 +accessInstanceVariablesDirectly 方法并返回 NO 就可以组织这种行为。

这使得我们调用valueForKey:@”numbers”时,KVC会为我们返回一个可以响应NSArray所有方法的代理数组对象(NSKeyValueArray),这是NSArray的子类,- (NSUInteger)countOfNumbers决定了这个代理数组的容量,- (id)objectInNumbersAtIndex:(NSUInteger)index决定了代理数组的内容。本例中使用的key是numbers,同理的如果key叫boxes,KVC就会去寻找-countOfBoxes: ,你得按照标准方式命名方法KVC才能构建方法名,这也是为什么获取方法必须以小写字母开头的原因。

对于可变容器属性,我们也可以在可变集合(NSMutableArray、NSMutableSet、NSMutableOrderedSet)中使用集合代理可以使用下面这样用 mutator(改变属性)方法:

或者可以通过调 mutableArrayValueForKey: 或 mutableSetValueForKey:返回一个特殊的代理对象,修改这个对象会自动对对象调用合适的KVC方法。

打印结果
2016-05-30 16:13:52.386 DCRequestTest[7334:177263] insert 这是个数n
2016-05-30 16:13:52.386 DCRequestTest[7334:177263] first log n (
“\U8fd9\U662f\U4e2a\U6570”
)
2016-05-30 16:13:52.387 DCRequestTest[7334:177263] remove
2016-05-30 16:13:52.387 DCRequestTest[7334:177263] second log n (
)

该例子中 ,我们调用

KVC会给我们返回一个代理可变容器threeTimes,通过对代理可变容器的操作,KVC会自动调用合适KVC方法(如下):

间接地对被代理对象操作。
还有一组更强大的方法供参考

转载请注明:怼码人生 » iOS中的键值编码(KVC)与观察(KVO)(二)

喜欢 (0)
发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址