KVC
KVC是key Value Coding的縮寫,主要方法有setValue:forKey和valueForKey:。
setValue:forKey:主要是賦值。value參數是值,key參數是變量名。
eg:[student setValue:@”張3”forKey:@”name”];
給student的name屬性賦值為張3 。
valueForKey: 主要是取值。key是變量名,方法返回變量的值。
setValue:forKeyPath:可以通過“.”的方式,給私有的自定義類型的私有變量賦值。
eg:[student setValue:@”LI4” forKeyPath:@”person.name”];
利用KVC機制,可以給繼承于NSObject類的私有變量賦值。
注意:
key里面的屬性,是什么類型,value對應的就應該是什么類型。
key里面的屬性,一定要是類的屬性,否則會報錯。
主要用在多個類,對象嵌套的時候。
譬如:
我們有一個人 這個人有一個手機類 這個手機類 有一個電池類 我們要獲取這個電池類 比之前復雜了吧。
沒有KVC
Persion *persion =[ [Persion alloc] init ];
Phone *phone = persion.phone;
Battery *battery = phone.battery;
一:使用KVC
Battery *battery = [persion valueForKeyPath: @"phone.battery" ];
注意- valueForKeyPath 里面的值是區分大小寫的,你如果寫出Phone.Battery 是不行的.
KVC 最常用的還是在序列化和反序列話對象。我們經常需要把json字符串反序列化成我們想要的對象 下面是一個例子 將字典用NSKeyedArchiver 序列化成對象
- (id)initWithDictionary:(NSDictionary *)dictionary {
self = [self init];
if (self){
[self setValuesForKeysWithDictionary:dictionary];
}
return self;
}
注意 這里有一個坑 當我們setValue 給一個沒有定義的字典值(forUndefinedKey)時 會拋出NSUndefinedKeyException異常的 記的處理此種情況.
還有一個需要注意的是KVC 并沒有類型檢驗,畢竟Object-C 還是動態的啦。 還是看下面的代碼吧
[persion setValue:[NSNumber numberWithInteger:1] forKey:@"name"];
// compiles and runs
persion.name = [NSNumber numberWithInteger:1];
// won't compile: Incompatible pointer types assigning to 'NSString *' from 'NSNumber *'
setValue forKey 得到的對象是泛型的id, 只有在使用的時候才能確定類型。你可能會問不至于吧 OC 這樣弱啊,當然不是 OC 提供了了一個方法validateValue來解決這個問題
@property (nonatomic, strong) NSString name;
- (BOOL)validateName:(id*)ioValue error:(NSError**)error {
// Validation logic goes here
}
Person *p = [Person new];
NSString *name = @"Jason Hu";
NSError *error = nil;
// This call below actually calls our validateName: error: method
if ([p validateValue:&name forKey:@"name" error:&error]) {
[p setValue:name forKey:@"name"];
}
你可能會問寫這樣多代碼 才只驗證了一個屬性 那如果我這個類有n+個屬性 難道我要寫n+個驗證方法嗎?
二:KVC 驗證
到這里我們對KVC已經有了一個初步印象,到這里其實還只是冰山一角。
下面我們要提高更高的要求,如果讓key 支持 不區分大小寫
下面我們提到一個方法initialize
initialize是在類或者其子類的第一個方法被調用前調用。所以如果類沒有被引用進項目或者類文件被引用進來,但是沒有使用,那么initialize也不會被調用 ,到這里 知道我們接下來要干嘛了吧
+ (void)initialize {
[super initialize];
dispatch_once(&onceToken, ^{
modelProperties = [NSMutableDictionary dictionary];
propertyTypesArray = @[/* removed for brevity */];
});
NSMutableDictionary *translateNameDict = [NSMutableDictionary dictionary];
[self hydrateModelProperties:[self class] translateDictionary:translateNameDict];
[modelProperties setObject:translateNameDict forKey:[self calculateClassName]];
}
+ (void)hydrateModelProperties:(Class)class translateDictionary:(NSMutableDictionary *)translateDictionary {
if (!class || class == [NSObject class]){
return;
}
unsigned int outCount, i;
objc_property_t *properties = class_copyPropertyList(class, &outCount);
for (i = 0; i < outCount; i++){
objc_property_t p = properties[i];
const char *name = property_getName(p);
NSString *nsName = [[NSString alloc] initWithCString:name encoding:NSUTF8StringEncoding];
NSString *lowerCaseName = [nsName lowercaseString];
[translateDictionary setObject:nsName forKey:lowerCaseName];
//注意此處哦
NSString *propertyType = [self getPropertyType:p];
[self addValidatorForProperty:nsName type:propertyType];
}
free(properties);
[self hydrateModelProperties:class_getSuperclass(class) translateDictionary:translateDictionary];
}
KVO
Key-Value Observing (簡寫為KVO):當指定的對象的屬性被修改了,允許對象接受到通知的機制。每次指定的被觀察對象的屬性被修改的時候,KVO都會自動的去通知相應的觀察者,相當于設計模式中的觀察者模式。
KVO的優點:
當有屬性改變,KVO會提供自動的消息通知。這樣的架構有很多好處。首先,開發人員不需要自己去實現這樣的方案:每次屬性改變了就發送消息通知。這是KVO 機制提供的最大的優點。因為這個方案已經被明確定義,獲得框架級支持,可以方便地采用。開發人員不需要添加任何代碼,不需要設計自己的觀察者模型,直接可 以在工程里使用。其次,KVO的架構非常的強大,可以很容易的支持多個觀察者觀察同一個屬性,以及相關的值。
KVO是Key Value Observer的縮寫,主要方法是addObserver:forKeyPath:options:context:和observeValueForPath:ofObject:change:context。
addObserver:forKeyPath:options:context:注冊監聽事件。
observeValueForPath:ofObject:change:context當注冊的值,利用KVC發生改變的時候,就會觸發這個方法。
在最后的dealloc方法里面,要記得移除監聽事件。
補充:iOS之KVC和KVO
一、KVC(key-value-coding)
1、只針對類屬性,設置鍵值對
2、設置setValue: forKey:,即forKey只能為類屬性
3、取值valueForKey
二、KVO(key-value-observing)被觀察者的屬性發生改變時,通知觀察者
1、利用KVC對類屬性進行設置
2、注冊observing對象addObserver:forKeyPath:options:context:
3、觀察者類必須重寫方法?observeValueForKeyPath:ofObject:change:context:
4、應用,MVC模型中,數據庫(dataModal)發生變化時,引起view改變,用這種方式實現非常方便