KVC、KVO探識(shí)(二)KVC你不知道的東西

前言

最近在寫關(guān)于KVC、KVO的一些東西,也許很多人都認(rèn)為KVC再簡(jiǎn)單不過了,其實(shí)不是這個(gè)樣子的,因?yàn)槲乙郧案蟛糠秩说南敕ㄊ且粯拥?,KVC、KVO固定的書寫模式,調(diào)用也超級(jí)簡(jiǎn)單。其實(shí)不是的,因?yàn)樵绞呛?jiǎn)單的東西,越是容易被人忽略。現(xiàn)在就給大家分享一些關(guān)于KVC你可能不知道的東西。

KVC的賦值原理

setValue:forKey:賦值原理如下:

  1. 去模型中查找有沒有對(duì)應(yīng)的setter方法:例如:setIcon方法,有就直接調(diào)用這個(gè)setter方法給模型這個(gè)屬性賦值[self setIcon:dic[@"icon"]];
  2. 如果找不到setter方法,接著就會(huì)去尋找有沒有icon屬性,如果有,就直接訪問模型中的icon屬性,進(jìn)行賦值,icon=dict[@"icon"];
  3. 如果找不到icon屬性,接著又會(huì)去尋找_icon屬性,如果有,直接進(jìn)行賦值_icon=dict[@"icon"];
  4. 如果都找不到就會(huì)報(bào)錯(cuò):[<Flag 0X7fb74bc7a2c0> setValue:forUndefinedKey:]
擴(kuò)展

讀者可以去查查KVV(鍵值驗(yàn)證),進(jìn)一步理解報(bào)錯(cuò)原因與容錯(cuò)方法。

KVC開關(guān)及檢查
  • 如果對(duì)某個(gè)類,不允許使用KVC,可以通過設(shè)置 accessInstanceVariablesDirectly 控制。

    // 在該類的內(nèi)部,重寫此方法,外部使用KVC時(shí),禁用沒有寫set get 方法的屬性值。
    // 注意:對(duì)于 @property 定義的屬性可以 KVC+   
    -(BOOL)accessInstanceVariablesDirectly{ 
      return NO;
    }
    
  • 賦值檢查
    // 在類的內(nèi)部,進(jìn)行檢查,不符合要求 返回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;
    }
    }
    //用法:
    // 外部 使用時(shí),先判斷是否符合要求,再使用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為模型賦值(與昨天的有極大的差別)

昨天:昨天的情況,后臺(tái)返回的json與模型變量名一致。
今天:如果后臺(tái)給我們返回的一些json字符串,與我們的model屬性一部分不一致(或者json包含關(guān)鍵字)。
簡(jiǎn)單的說:如果json里面的某些key就是和object的property名字不一樣呢,或者有些server返回的字段是objc保留字如”id”, “description”等, 我們也希望也map dict to object, 這時(shí)候我們就需要用上setValue:forUndefinedKey, 因?yàn)槿绻覀儾惶幚磉@些Undefined Key,還是用setValuesForKeysWithDictionary就會(huì) 拋出異常。

  -(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];
             } 
  } 

所以只要重載這個(gè)方法,就可以處理了那些無法跟property相匹配的key了,默認(rèn)的實(shí)現(xiàn)是拋出一個(gè)NSUndefinedKeyException。

KVC處理包含類內(nèi)部包含類的情況(重寫setValue:forKey:)

如果這時(shí)候server返回的People有了內(nèi)嵌的json(如Products{product1{count:xx, sumPrice:xx}}, product2{} ….),又該怎么辦,能把這個(gè)內(nèi)嵌的json轉(zhuǎn)化成我們的客戶端的Product類嘛, 當(dāng)然可以這時(shí)候就需要重載setValue:forKey, 單獨(dú)處理”Products”這個(gè)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]; 
    } 
  } 

}
從這一點(diǎn)中可以知道,setValuesForKeysWithDictionary內(nèi)部調(diào)用了setValue:forKey:方法。

keyPath的巧妙用法

情景:我們需要把一個(gè)數(shù)組里的People的名字的首字母大寫,并且把新的名字存入新的數(shù)組, 這時(shí)候通常做法會(huì)是遍歷整個(gè)數(shù)組,然后把每個(gè)People的name取出來,調(diào)用 capitalizedString 然后把新的String加入新的數(shù)組中。 有了KVC就有了新做法:

[array valueForKeyPath:@"name.capitalizedString"]

疑問:為什么用valueForKeyPath, 不用valueForKey?
因?yàn)?/strong>:valueForKeyPath可以傳遞關(guān)系,例如這里是每個(gè)People的name property的String的capitalizedString property, 而valueForKey不能傳遞這樣的關(guān)系,所以對(duì)于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

未完待續(xù)……

歡迎關(guān)注我的個(gè)人微信公眾號(hào),免費(fèi)送計(jì)算機(jī)各種最新視頻資源!你想象不到的精彩!


0.jpg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容