iOS – 反射

运动互联网下iOS客户端的付出,一般都会与服务端举办报道,也会利用到Sqlite数据库来保存一些数据,按正常的搞法,一般都急需手动建表结构,写实体类对象,然后写插入、更新、查询等语句来兑现效益,因而想到是否有一种通用的法子来拓展部分代码方面的减负工作。利用反射的建制,可以很便利的贯彻。

首先,我们开展了以下的预约:

  1. sqlite的数据库表名直接利用实体类的类名;
  2. sqlite的数目字段使用实体类的属性名称;
  3. sqlite的数据类型统一设为text(引起sqlite这种文本数据库是动态类型的,存储的真面目都是文本)
  4. 实体类的系列统一都设为NSString

做如上的预定,只是缩小使用过程中,由于品种的例外造成不必要的劳动,假若要匡助各个类型,需要编制各个判断代码,举行格式的处理,有趣味的同窗能够更进一步研商。

先增加了NSObject,名称叫NSObject+Property,然后添加下面代码。

  1. 应用反射取得NSObject的属性,并存入到数组中

     - (NSArray *)getPropertyList: (Class)clazz
     {
         u_int count;
         objc_property_t *properties = class_copyPropertyList(clazz, &count);
         NSMutableArray *propertyArray = [NSMutableArray arrayWithCapacity:count];
    
         for (int i = 0; i < count ; i++)
         {
         const char* propertyName = property_getName(properties[i]);
         [propertyArray addObject: [NSString stringWithUTF8String: propertyName]];
         }
         free(properties); 
         return propertyArray;
     }
    
  2. 据悉属性生成创造Sqlite表的说话

     - (NSString *)tableSql:(NSString *)tablename
     {
         NSMutableString *sql = [[NSMutableString alloc] init];
         NSArray *array = [self getPropertyList];
         [sql appendFormat:@"create table %@ (",tablename] ;
         NSInteger i = 0;
         for (NSString *key in array) {
         if (i>0) {
         [sql appendString:@","];
         }
         [sql appendFormat:@"%@ text",key];
         i++;
         }
         [sql appendString:@")"];
         return sql;
     }
    
  3. 把一个实体对象,封装成字典Dictionary

     - (NSDictionary *)convertDictionary
     {
         NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
         NSArray *propertyList = [self getPropertyList];
         for (NSString *key in propertyList)
         {
             SEL selector = NSSelectorFromString(key);
    
             #pragma clang diagnostic push
             #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
             id value = [self performSelector:selector];
             #pragma clang diagnostic pop
    
             if (value == nil)
             {
                 value = [NSNull null];
             }
    
             [dict setObject:value forKey:key];
         }
         return dict;
     }
    
  4. 从一个字典中还原成一个实体对象

     - (void)dictionaryForObject:(NSDictionary*) dict
     {
         for (NSString *key in [dict allKeys])
         {
             id value = [dict objectForKey:key];
    
             if (value==[NSNull null])
             {
                 continue;
              }
             if ([value isKindOfClass:[NSDictionary class]]) 
             {
                 id subObj = [self valueForKey:key];
                 if (subObj)
                      [subObj dictionaryForObject:value];
             }
             else
             {
                 [self setValue:value forKeyPath:key];
             }
         }
     }
    
  5. 重回一个目的的门类名称

    • (NSString *)className
      {

        return [NSString stringWithUTF8String:object_getClassName(self)];
      

      }

以上是对NSObject的一个恢宏,使用了Obj-C的Category特性

以下是与数量存储相关,定义为DbHelper,对sqlite举行操作

  1. 把id类型的数码对象插入到数码

     -(void)insertObject:(id)object
     {
         NSString *tablename = [object className];
         NSMutableString *sql = [[NSMutableString alloc] init];
         NSArray *array = [object getPropertyList];
         [sql appendFormat:@"insert into %@ (",tablename] ;
         NSInteger i = 0;
         for (NSString *key in array) 
         {
             if (i>0) {
                  [sql appendString:@","];
             }
             [sql appendFormat:@"%@",key];
             i++;
         }
         [sql appendString:@") values ("];
         NSMutableArray *arrayValue = [NSMutableArray array];
         i=0;
         for (NSString *key in array)
         {
             SEL selector = NSSelectorFromString(key);
    
             #pragma clang diagnostic push
             #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
             id value = [object performSelector:selector];
             #pragma clang diagnostic pop
             if (value==nil) 
             {
                  value = @"";
             }
             [arrayValue addObject:value];
             if (i>0)
             {
                  [sql appendString:@","];
             }
             [sql appendString:@"?"];
             i++;
         }
         [sql appendString:@")"];
         [_db executeUpdate:sql withArgumentsInArray:arrayValue];
     }
    
  2. 把字典NSDictionary对象插入到数据库中
    在与服务器举办交互时候,大家一般采取Json举行数据通讯,从服务端获取Json字符,通过JSON基特(Kit)框架,反类别化成NSDictionary对象,然后插入到数据库
    变动插入的sql语句

     -(NSString *)createInsertSqlByDictionary:(NSDictionary *)dict tablename:(NSString *)table
     {
    
         NSMutableString *sql = [[NSMutableString alloc] init];
         [sql appendFormat:@"insert into %@ (",table] ;
         NSInteger i = 0;
         for (NSString *key in dict.allKeys)
         {
             if (i>0) {
                 [sql appendString:@","];
             }
             [sql appendFormat:@"%@",key];
             i++;
         }
         [sql appendString:@") values ("];
         i = 0;
         for (NSString *key in dict.allKeys) 
         {
             if (i>0) 
             {
                  [sql appendString:@","];
             }
             [sql appendFormat:@":%@",key];
             i++;
         }
         [sql appendString:@")"];
         return sql;
     }
    

把字典插入到数据库中

    -(void)insertBySql:(NSString *)sql dict:(NSDictionary *)dict
    {
        if (sql && sql.length>0) {
            [_dbQueue inDatabase:^(FMDatabase *db) {
            [db executeUpdate:sql withParameterDictionary:dict];
            }];
        }
    }

取数据

  1. 从数据库取多少,封装成成字典,然后放入到数组中

     -(NSArray *)queryDbToDictionaryArray:(NSString *)tablename sql:(NSString *)sql
     {
         FMResultSet *resultSet=[_db executeQuery:sql];
         NSArray *columnArray = [self fMSetColumnArray:resultSet];
         NSMutableArray *syncArray = [[NSMutableArray alloc] init];
         NSString *columnName = nil;
         while ([resultSet next])
         {
             NSMutableDictionary *syncData = [[NSMutableDictionary alloc] init];
             for(int i =0;i<columnArray.count;i++)
             {
                 columnName = [columnArray objectAtIndex:i];
                 NSString *columnValue = [resultSet stringForColumn: columnName];
                 if (columnValue==nil)
                 {
                     columnValue=@"";
                 }
                 [syncData setObject:columnValue forKey:columnName];
             }
             [syncArray addObject:syncData];
         }
             if ([syncArray count]==0) 
             {
                  return nil;
             }
    
         return syncArray;
     }
    
  2. 从数据库中取数据,封装成对象,然后放入数组中

     -(NSArray *)queryDbToObjectArray:(Class )clazz sql:(NSString *)sql
     {
         FMResultSet *resultSet=[_db executeQuery:sql];
         NSArray *columnArray = [self fMSetColumnArray:resultSet];
         NSMutableArray *syncArray = [[NSMutableArray alloc] init];
         NSString *columnName = nil;
         while ([resultSet next])
         {
             NSObject *obj = [[clazz alloc] init];
    
             if (obj==nil)
             {
                  continue;
             }
    
             for(int i =0;i<columnArray.count;i++)
             {
                 columnName = [columnArray objectAtIndex:i];
                 NSString *columnValue = [resultSet stringForColumn: columnName];
                 SEL selector = NSSelectorFromString(columnName);
    
                 if ([obj respondsToSelector:selector])
                 {
                      [obj setValue:columnValue forKeyPath:columnName ];
                 }
             }
             [syncArray addObject:obj];
         }
         if ([syncArray count]==0) 
         {
             return nil;
         }
         return syncArray;
     }
    

在数据量很大时候,考虑到性能问题,此方法需要讨论采纳。

有了这么些东西,举行开发就节省了成百上千时间和代码量,间接动态生成表,从服务端接口取到数据,直接插入到数据库中保留,显示数据时,从数据库中取出数据放入到对象数组中。

网站地图xml地图