学习了iOS有一段时间了,使用到fmdb操作数据库的时候感觉有很多重复性的工作要做,查询数据库时面向对象性感觉很差,一个查询只能针对一个Model,经过了解发现了runtime的使用可以解决这一问题。
使用fmdb的时候相信有过这样的经历查询某个model时:
NSString *sql = @"select * from myFmdb"; FMResultSet *set = [self.database executeQuery:sql]; while (set.next) { int pid = [set intForColumn:@"id"]; <span style="color:#ff0000;">NSString *name = [set stringForColumnIndex:1]; NSInteger age = [set intForColumn:@"age"];</span> NSLog(@"id==%d,name==%@,age==%ld",pid,name,age); }
其中红色的代码是查询的某一个字段,我们不仅要知道字段的类型还要知道字段的位置,用起来就很不方便,而如果model类发生了改变那查询语句也随之改变才行。简单使用runtime可解决此类问题。
使用runtime代码如下(写成了一个方法):
- (NSMutableArray *)finAllWithSql:(NSString *)tableName fmdb:(FMDatabase *)db model:(Class)cls{ //创建要返回的数组 NSMutableArray *data = [NSMutableArray array]; //根据表明查询数据库 NSString *sql = [NSString stringWithFormat:@"select * from %@",tableName]; //根据第三方的FMdatabase查询结果集 FMResultSet *set = [db executeQuery:sql]; //获取该model类的所有的属性列表 unsigned int count = 0; Ivar *ivars = class_copyIvarList(cls, &count); //遍历 while ([set next]) { //根据传进来的类cls,创建对应的对象并保存. id obj = [[cls alloc] init]; //遍历所有的属性变量 for (int i=0; i<count; i++) { //得到该属性 Ivar ivar = ivars[i]; const char *type = ivar_getTypeEncoding(ivar); //的到属性的类型用于判断 NSString *valueType = [NSString stringWithCString:type encoding:NSUTF8StringEncoding]; //得到属性的name使用setKey来设置值,要把属性那么前面的"_"去掉. NSString *proName = [NSString stringWithCString:ivar_getName(ivar) encoding:NSUTF8StringEncoding]; NSString *name = [proName componentsSeparatedByString:@"_"][1]; //判断属性类型,这里仅考虑了NSString,int和float类型(这里吧float转化为了double) if ([valueType hasPrefix:@"@"]) { //这是NSString类型的,设置值 [obj setValue:[set stringForColumnIndex:i] forKey:name]; }else if([valueType hasPrefix:@"q"]|[valueType hasPrefix:@"i"]){ //"q"代表的是NSInteger类型,这是NSInteger类型的,设置值 [obj setValue:@([set intForColumnIndex:i]) forKey:name]; }else if ([valueType hasPrefix:@"f"]){ //这是float类型的,设置值 [obj setValue:@([set doubleForColumnIndex:i]) forKey:name]; } } //将该字典存储到数组中. [data addObject:obj]; } return data; }
现对以上代码进行说明,首先传进来的参数有查询的表名,要查询的数据库以及查询的model类,使用fmdb查询后得到查询结果集,通过
unsigned int count = 0; Ivar *ivars = class_copyIvarList(cls, &count);
得到model类的属性列表,然后遍历结果集,然后遍历属性列表的属性,
const char *type = ivar_getTypeEncoding(ivar);
得到的是属性的类型,之后的几条语句是将这个类型进行处理以用于判断,if语句是用于判断属性类型的,这里仅仅只是展示了三种类型,把属性值通过setValue forKey的方式复制给通过传进来的参数cls创建的类,然后保存到数组中。最后返回数组。
可以看出要想查询结果只要传进来几个参数就行了,最后返回的数组保存的是id类型的,用的时候强转一下就好了。
第一次写博客,希望方便大家学习,也方便自己学习进步,望大家指教。runtime的使用还是菜鸟,很多地方也有待改正望大神斧正。其实也可以封装sqlite的,只是写的时候就写成了这个样子。
时间: 2024-11-06 07:24:10