C---OCKVC和KVO

KVC、KVO探识(二)KVC你不知道的东西

2016-03-26  本文已影响477人  Peak_One
前言

最近在写关于KVC、KVO的一些东西,也许很多人都认为KVC再简单不过了,其实不是这个样子的,因为我以前跟大部分人的想法是一样的,KVC、KVO固定的书写模式,调用也超级简单。其实不是的,因为越是简单的东西,越是容易被人忽略。现在就给大家分享一些关于KVC你可能不知道的东西。

KVC的赋值原理

setValue:forKey:赋值原理如下:

  1. 去模型中查找有没有对应的setter方法:例如:setIcon方法,有就直接调用这个setter方法给模型这个属性赋值[self setIcon:dic[@"icon"]];
  2. 如果找不到setter方法,接着就会去寻找有没有icon属性,如果有,就直接访问模型中的icon属性,进行赋值,icon=dict[@"icon"];
  3. 如果找不到icon属性,接着又会去寻找_icon属性,如果有,直接进行赋值_icon=dict[@"icon"];
  4. 如果都找不到就会报错:[<Flag 0X7fb74bc7a2c0> setValue:forUndefinedKey:]
扩展

读者可以去查查KVV(键值验证),进一步理解报错原因与容错方法。

KVC开关及检查
KVC通过Dictionary为模型赋值(与昨天的有极大的差别)

昨天:昨天的情况,后台返回的json与模型变量名一致。
今天:如果后台给我们返回的一些json字符串,与我们的model属性一部分不一致(或者json包含关键字)。
简单的说:如果json里面的某些key就是和object的property名字不一样呢,或者有些server返回的字段是objc保留字如”id”, “description”等, 我们也希望也map dict to object, 这时候我们就需要用上setValue:forUndefinedKey, 因为如果我们不处理这些Undefined Key,还是用setValuesForKeysWithDictionary就会 抛出异常。

  -(void)setValue:(id)value forUndefinedKey:(NSString *)key 
  { 
      if([key isEqualToString:@"nameXXX"]) 
      self.name = value; 
      if([key isEqualToString:@"ageXXX"]) {
          self.age = value; 
      }else{ 
           [super setValue:value forKey:key];
             } 
  } 

所以只要重载这个方法,就可以处理了那些无法跟property相匹配的key了,默认的实现是抛出一个NSUndefinedKeyException。

KVC处理包含类内部包含类的情况(重写setValue:forKey:)

如果这时候server返回的People有了内嵌的json(如Products{product1{count:xx, sumPrice:xx}}, product2{} ….),又该怎么办,能把这个内嵌的json转化成我们的客户端的Product类嘛, 当然可以这时候就需要重载setValue:forKey, 单独处理”Products”这个key, 把它wrapper成我们需要的class

-(void) setValue:(id)value forKey:(NSString *)key 
{ 
  if([key isEqualToString:@"products"]) 
  { 
    for(NSMutableDictionary *productDict in value) 
    { 
      Prodcut *product = [[Product alloc] initWithDictionary:prodcutDict]; 
      [self.products addObject:product]; 
    } 
  } 

}
从这一点中可以知道,setValuesForKeysWithDictionary内部调用了setValue:forKey:方法。

keyPath的巧妙用法

情景:我们需要把一个数组里的People的名字的首字母大写,并且把新的名字存入新的数组, 这时候通常做法会是遍历整个数组,然后把每个People的name取出来,调用 capitalizedString 然后把新的String加入新的数组中。 有了KVC就有了新做法:

[array valueForKeyPath:@"name.capitalizedString"]

疑问:为什么用valueForKeyPath, 不用valueForKey?
因为:valueForKeyPath可以传递关系,例如这里是每个People的name property的String的capitalizedString property, 而valueForKey不能传递这样的关系,所以对于dict里面的dict, 我们也只能用valueForKeyPath。

KVC的一些其他用法
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)
- (NSMutableArray *)mutableArrayValueForKey:(NSString *)key; 
- (NSMutableOrderedSet *)mutableOrderedSetValueForKey:(NSString *)key NS_AVAILABLE(10_7, 5_0); 
- (NSMutableSet *)mutableSetValueForKey:(NSString *)key;- (nullable id)valueForKeyPath:(NSString *)keyPath;
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;
- (BOOL)validateValue:(inout id __nullable * __nonnull)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;- (NSDictionary<NSString *, id> *)dictionaryWithValuesForKeys:(NSArray<NSString *> *)keys;
- (void)setValuesForKeysWithDictionary:(NSDictionary<NSString *, id> *)keyedValues;
@end
@interface NSArray<ObjectType>(NSKeyValueCoding)
- (id)valueForKey:(NSString *)key;
- (void)setValue:(nullable id)value forKey:(NSString *)key;
@end
@interface NSDictionary<KeyType, ObjectType>(NSKeyValueCoding)
- (nullable ObjectType)valueForKey:(NSString *)key;
@end
@interface NSMutableDictionary<KeyType, ObjectType>(NSKeyValueCoding)
- (void)setValue:(nullable ObjectType)value forKey:(NSString *)key;
@end
@interface NSOrderedSet<ObjectType>(NSKeyValueCoding)
- (id)valueForKey:(NSString *)key NS_AVAILABLE(10_7, 5_0);- (void)setValue:(nullable id)value forKey:(NSString *)key NS_AVAILABLE(10_7, 5_0);
@end
@interface NSSet<ObjectType>(NSKeyValueCoding)
- (id)valueForKey:(NSString *)key;
- (void)setValue:(nullable id)value forKey:(NSString *)key;
@end

未完待续……

上一篇下一篇

猜你喜欢

热点阅读