拥有一个自己的模型基类。
在进行数据获取的时候会将数据使用模型进行存储,我常规的方法都是给一两个遍历初始化方法,在在里面对字典进行取值赋给相应的模型属性。
这样的好处也有,就是代码直观,快速。由于模型的属性一般是根据网络或者数据库获得的json进行设定的,所以可以考虑使用KVC,而且如果一个模型有很多个属性的话,这样写也比较麻烦。
而使用runtime可以不用考虑属性的个数(有点儿像KVC,但是这只是对runtime的一次练习使用,所以就用了runtime),这样的做法是可以得到一个自己的模型基类,重用性大大提升.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
   | #pragma mark - convenience
 
 
  - (instancetype) initWithDict:(NSDictionary *)dict{
      self = [super init];     if (self) {         [self assginToPropertyWithDictionary:dict];         [self assginToRuntimePropertyWithDictionary:dict];     }     return self; } + (instancetype) itemWithDict:(NSDictionary *)dict{
      return [[self alloc] initWithDict:dict]; }
   | 
 
下面有两种方法进行模型属性的赋值,第一种是使用runtime得到模型的所有属性,然后还用KVC进行赋值,第二种是在cocoaChina上看到的一个方法,是得到对应属性的setter方法,然后对属性进行赋值,两种都来感受一下,后面会说两种方法的不同。
runtime
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
   | - (void) assginToRuntimePropertyWithDictionary:(NSDictionary *)dict{         if (dict == nil) {         return;     }         NSArray * allKeys = dict.allKeys;         unsigned int outCount;     objc_property_t * propertys = class_copyPropertyList(self.class, &outCount);         for (int index = 0; index < outCount; index ++) {         objc_property_t property = propertys[index];                 NSString * propertyKey = [NSString stringWithUTF8String:property_getName(property)];                 if ([allKeys containsObject:propertyKey]) {                          id propertyValue = [dict objectForKey:propertyKey];             [self setValue:propertyValue forKey:propertyKey];         }     }     free(propertys); }
  | 
 
cocoaChina
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
   | - (void) assginToPropertyWithDictionary:(NSDictionary *)dict{
      if (dict == nil) {         return;     }         NSArray * allKeys = dict.allKeys;         for (int index = 0; index < allKeys.count; index ++) {                 SEL setSEL = [self creatSetterWithPropertyName:allKeys[index]];                 if ([self respondsToSelector:setSEL]) {                         NSString * value = [dict objectForKey:allKeys[index]];                         [self performSelectorOnMainThread:setSEL                                    withObject:value                                 waitUntilDone:[NSThread isMainThread]];         }     } }
 
 
 
  - (SEL) creatSetterWithPropertyName:(NSString *)propertyName{         propertyName = propertyName.capitalizedString;         NSString * setterName = [NSString stringWithFormat:@"set%@:",propertyName];         return NSSelectorFromString(setterName); }
  | 
 
在模型的属性为一般的常规属性(id)的时候,比如,NSString,NSArray,NSDictionary等的时候两个方法都可以正确的完成属性赋值。
但是在基本数据类型的属性(非id)的时候,比如,NSInterger,BOOL,int等的时候,由于第二个就必须要进行解包和封包,因此导致不能正确的进行属性赋值,而第一个不论是否进行封包都能够正确进行属性赋值。
因此还是推荐使用runtime进行属性赋值。
一个不可控制的情况是有的时候还是会遇到字典的key和模型的属性不同,这时候的解决办法是需要在类中建立key和属性的映射关系。
在模型基类中写如下方法
1 2 3 4 5 6 7 8
   | 
 
 
 
  -(NSDictionary *) propertyMapDic {     return nil; }
 
  | 
 
该方法在有需要的子类中进行重写,设置映射规则
1 2 3 4 5
   | -(NSDictionary *) propertyMapDic{         return @{@"firstName":@"key1",              @"address":@"key3"}; }
  | 
 
然后在模型基类中实现如下方法,将有映射的字典对原字典进行重新设值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
   | 
 
 
 
 
  - (void) dictionaryMapPropertyWithAllKeys:(NSMutableArray *)allKeys toNewDictionary:(NSMutableDictionary *)newDict{         NSDictionary * mapDictionary = [self propertyMapDic];         if (mapDictionary) {                           [mapDictionary enumerateKeysAndObjectsUsingBlock:^(NSString * mapProperty, NSString * mapKey, BOOL *stop) {             if ([allKeys containsObject:mapKey]) {
                  [newDict setValue:[newDict objectForKey:mapKey] forKey:mapProperty];                 [newDict removeObjectForKey:mapKey];                                 NSUInteger mapIndex = [allKeys indexOfObject:mapKey];                 [allKeys replaceObjectAtIndex:mapIndex withObject:mapProperty];             }         }];     }  }
 
  | 
 
此时的runtimeAssginToPropertyWithDictionary:方法如下,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
   | - (void) runtimeAssginToPropertyWithDictionary:(NSDictionary *)dict{     	         NSMutableDictionary * newDict = [NSMutableDictionary dictionaryWithDictionary:dict];         for (int index = 0; index < outCount; index ++) {                	        	                  [self dictionaryMapPropertyWithAllKeys:allKeys toNewDictionary:newDict];                 if ([allKeys containsObject:propertyKey]) {         	         }     }     free(propertys); }
  | 
 
这里是自己练习的一个App,作用是仿照快起做的一个快速启动手机上的软件。里面有简单的对控制器的数据源封装。