美文网首页C---OCKVC和KVO
KVC、KVO探识(二)KVC你不知道的东西

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

作者: Peak_One | 来源:发表于2016-03-26 10:40 被阅读477次
    前言

    最近在写关于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,可以通过设置 accessInstanceVariablesDirectly 控制。

      // 在该类的内部,重写此方法,外部使用KVC时,禁用没有写set get 方法的属性值。
      // 注意:对于 @property 定义的属性可以 KVC+   
      -(BOOL)accessInstanceVariablesDirectly{ 
        return NO;
      }
      
    • 赋值检查
      // 在类的内部,进行检查,不符合要求 返回NO ,提供外部参考。
      - (BOOL)validateValue:(inout id _Nullable __autoreleasing *)ioValue forKey:(NSString *)inKey error:(out NSError * _Nullable __autoreleasing )outError{
      if ([inKey isEqualToString:@"colors"] && [
      ioValue isKindOfClass:[NSArray class]]) {
      return YES;
      } else {
      return NO;
      }
      }
      //用法:
      // 外部 使用时,先判断是否符合要求,再使用KVC。
      NSError *error;
      NSString *apoint = @"name";
      if ([aPerson validateValue:&apoint forKey:@"_colors" error:&error]) {
      NSLog(@"可以赋值 apoint");
      [aPerson setValue:apoint forKey:@"_colors"];
      } else {
      NSLog(@"不可以赋值 apoint");
      NSLog(@"%@",error.debugDescription);
      }

    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
    

    未完待续……

    相关文章

      网友评论

        本文标题:KVC、KVO探识(二)KVC你不知道的东西

        本文链接:https://www.haomeiwen.com/subject/meedlttx.html