天天看点

kvc和kvo的使用情况的了解

了解cocoa:Cocoa是苹果公司为Mac OS X所创建的原生面向对象的API,是Mac OS X上五大API之一(其它四个是Carbon、POSIX、X11和Java)。

苹果的面向对象开发框架,用来生成 Mac OS X 的应用程序。主要的开发语言为 Objective-c, 一个c 的超集。

即为:Coroa 基本面向原生的API抽象,是C的一个超级。

在Cocoa中是以被 万物之源NSObject类实现的NSKeyValueCoding(键值编码)/(键值观察)NSKeyValueObserving 非正式协议 的形式被定义为基础框架的一部分。=

NSKeyValueCoding 是一个非正式的协议。(线管的内容可以看西面罗列的方法)

KVC/KVO实现的根本是Objective-C的 动态性和runtime

KVC/KVO机制离不开访问器方法的实现。

kvc

类似c++中的map类的使用。

它提供了一种使用“字符串”而不是“访问器(方法)”方法去访问一个对象实例变量的机制。

kvo  

提供了一种当其它对象属性被修改的时候能通知当前对象的机制.

KVO机制很适合实现model和controller类之间的通讯。

总结所有的方法几乎可以使用下面的四个方法为代表。

//一般的都是这几个方法
<span style="color:#990000;">- (id)valueForKey:(NSString *)key;
- (void)setValue:(id)value forKey:(NSString *)key;</span>
Key——>键值 , 就是要访问的属性名称(key)对应的字符串。(用数组(索引)的方式似乎没有什么区别)

<span style="color:#CC0000;">- (id)valueForKeyPath:(NSString *)keyPath;
- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;</span>
后面的KeyPath是一个被点操作符隔开的用于访问对象的指定属性的字符串序列。(keypath 就是大范围到小范围逐渐到具体的地方)
eg:eyPath address.street将会访问消息接收对象所包含的address属性中包含的一个street属性。
其实KeyPath说白了就是我们平时使用点操作访问某个对象的属性时所写的那个字符串。
           

点语法和kvc之间的差别:

在实现了访问器方法的类中,使用点语法和KVC访问对象其实差别不大,二者可以任意混用。但是没有访问起方法的类中,点语法无法使用,这时KVC就有优势了。( 原因见第三部分的第一节:KVC如何访问属性值。 ) ??

一对多的关系:(数据中经常会存在)

 ①间接操作

先通过KVC方法取到集合属性,然后通过集合属性操作集合中的元素。

 ②直接操作 (基本上是不适用)

 4、键值验证(Key-Value Validation)

KVC提供了验证Key对应的Value是否可用的方法:

- (BOOL)validateValue:(inout id *)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;

该方法默认的实现是调用一个如下格式的方法:

- (BOOL)validate<Key>:error:

比如属性name对应的方法为:

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

    return ;

}

KVC是不会自动调用键值验证方法的 ,就是说我们需要手动验证。但是有些技术,比如CoreData会自动调用。

 5、KVC对数值和结构体型属性的支持

 总结一下,想使用KVO有三种方法:

1)使用了KVC

使用了KVC,如果有访问器方法,则运行时会在访问器方法中调用 will/didChangeValueForKey:方法;

没用访问器方法,运行时会在setValue:forKey方法中调用 will/didChangeValueForKey:方法。

2)有访问器方法

运行时会重写访问器方法调用 will/didChangeValueForKey:方法。

因此,直接调用访问器方法改变属性值时,KVO也能监听到。

3)显示调用will/didChangeValueForKey:方法。

总之,想使用KVO,只要有 will/didChangeValueForKey:方法就可以了。

③ _isKVOA

这个私有方法估计是用来标示该类是一个 KVO 机制声称的类。

优点和缺点

1、优点

①可以再很大程度上简化代码

例子网上很多,这就不举了

②能跟脚本语言很好的配合

才疏学浅,没学过AppleScript等脚本语言,所以没能深刻体会到该优点。

2、缺点

KVC的缺点不明显,主要的kvo的缺点如连接:http://www.mikeash.com/pyblog/key-value-observing-done-right.html

核心思想是说KVO的回调机制,不能传一个selector或者block作为回调,而必须重写-addObserver:forKeyPath:options:context:方法所引发的一系列问题。问了解决这个问题,作者还亲自实现了一个MAKVONotificationCenter类,代码见github:

https://github.com/mikeash/MAKVONotificationCenter

不过个人认为这只是苹果做的KVO不够完美,不能算是缺陷。

关于NSKeyValueCoding.h这个文件爱你的属性的了解。

#import <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSOrderedSet.h>
#import <Foundation/NSSet.h>

@class NSError, NSString;

FOUNDATION_EXPORT NSString *const NSUndefinedKeyException;
FOUNDATION_EXPORT NSString *const NSAverageKeyValueOperator;
FOUNDATION_EXPORT NSString *const NSCountKeyValueOperator;
FOUNDATION_EXPORT NSString *const NSDistinctUnionOfArraysKeyValueOperator;
FOUNDATION_EXPORT NSString *const NSDistinctUnionOfObjectsKeyValueOperator;
FOUNDATION_EXPORT NSString *const NSDistinctUnionOfSetsKeyValueOperator;
FOUNDATION_EXPORT NSString *const NSMaximumKeyValueOperator;
FOUNDATION_EXPORT NSString *const NSMinimumKeyValueOperator;
FOUNDATION_EXPORT NSString *const NSSumKeyValueOperator;
FOUNDATION_EXPORT NSString *const NSUnionOfArraysKeyValueOperator;
FOUNDATION_EXPORT NSString *const NSUnionOfObjectsKeyValueOperator;
FOUNDATION_EXPORT NSString *const NSUnionOfSetsKeyValueOperator;

@interface NSObject(NSKeyValueCoding)

+ (BOOL)accessInstanceVariablesDirectly;
- (id)valueForKey:(NSString *)key;
- (void)setValue:(id)value forKey:(NSString *)key;
- (BOOL)validateValue:(inout id *)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;
- (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;
- (NSMutableOrderedSet *)mutableOrderedSetValueForKey:(NSString *)key NS_AVAILABLE(10_7, 5_0);
- (NSMutableSet *)mutableSetValueForKey:(NSString *)key;

- (id)valueForKeyPath:(NSString *)keyPath; //这个是有关路径的字符串,这个是怎么用的?

- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;
- (BOOL)validateValue:(inout id *)ioValue forKeyPath:(NSString *)inKeyPath error:(out NSError **)outError;

- (NSMutableArray *)mutableArrayValueForKeyPath:(NSString *)keyPath;
- (NSMutableOrderedSet *)mutableOrderedSetValueForKeyPath:(NSString *)keyPath NS_AVAILABLE(10_7, 5_0);
- (NSMutableSet *)mutableSetValueForKeyPath:(NSString *)keyPath;
- (id)valueForUndefinedKey:(NSString *)key;
- (void)setValue:(id)value forUndefinedKey:(NSString *)key;
- (void)setNilValueForKey:(NSString *)key;
- (NSDictionary *)dictionaryWithValuesForKeys:(NSArray *)keys;
- (void)setValuesForKeysWithDictionary:(NSDictionary *)keyedValues;
@end

//定的数组
@interface NSArray(NSKeyValueCoding)
- (id)valueForKey:(NSString *)key;
- (void)setValue:(id)value forKey:(NSString *)key;
@end

//字典的两种方式进行组合
@interface NSDictionary(NSKeyValueCoding)
- (id)valueForKey:(NSString *)key;
@end
@interface NSMutableDictionary(NSKeyValueCoding)
- (void)setValue:(id)value forKey:(NSString *)key;
@end

@interface NSOrderedSet(NSKeyValueCoding)
- (id)valueForKey:(NSString *)key;
- (void)setValue:(id)value forKey:(NSString *)key;
@end

@interface NSSet(NSKeyValueCoding)
- (id)valueForKey:(NSString *)key;
- (void)setValue:(id)value forKey:(NSString *)key;
@end

#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
//TARGET_OS_EMBEDDED这个表示是嵌入式的方式
//TARGET_OS_IPHONE iphone 开发
//TARGET_OS_MAC os系统开发

@interface NSObject(NSDeprecatedKeyValueCoding)
+ (BOOL)useStoredAccessor ;
- (id)storedValueForKey:(NSString *)key ;
- (void)takeStoredValue:(id)value forKey:(NSString *)key;
- (void)takeValue:(id)value forKey:(NSString *)key ;
- (void)takeValue:(id)value forKeyPath:(NSString *)keyPath ;
- (id)handleQueryWithUnboundKey:(NSString *)key;
- (void)handleTakeValue:(id)value forUnboundKey:(NSString *)key;
- (void)unableToSetNilForKey:(NSString *)key;
- (NSDictionary *)valuesForKeys:(NSArray *)keys ;
- (void)takeValuesFromDictionary:(NSDictionary *)properties;

@end
#endif