ios反射

http://www.cr173.com/html/18677_1.html

Obj-C语言开发iOS项目使用反射减少代码工作

最近在一个iOS项目中,利用到了Obj-c语言的运行时反射特性,来减少一些代码编写的工作量,特记录下来。
移动互联网下iOS客户端的开发,一般都会与服务端进行通讯,也会使用到Sqlite数据库来保存一些数据,按常规的搞法,一般都需要手动建表结构,写实体类对象,然后写插入、更新、查询等语句来实现功能,因此想到是否有一种通用的办法来进行一些代码方面的减负工作。通过这个项目的实践,已经找到了答案。

在使用这些代码前,我们进行了以下的约定:
1. sqlite的数据库表名直接使用实体类的类名;
2. sqlite的数据字段使用实体类的属性名称;
3. sqlite的数据类型统一设为text(引起sqlite这种文本数据库是动态类型的,存储的本质都是文本)
4. 实体类的类型统一都设为NSString

做以上的约定,只是减少使用过程中,由于类型的不同造成不必要的麻烦,如果要支持各种类型,需要编写各种判断代码,进行格式的处理,有兴趣的同学可以进一步研究,呵呵。

下面介绍几个重要的方法。

因为用到了Obj-c运行时的相关方法,所以需要导入运行时的头文件。
#import

直接扩展了NSObject,名称叫NSObject+Property,文章末尾提供文件下载。

@interface NSObject (Property)
@end

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,使用FMDB库对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字符,通过JSONKit框架,反序列化成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];
}];
}
}

取数据

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

-(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) {
[email protected]"";
}
[syncData setObject:columnValue forKey:columnName];
}
[syncArray addObject:syncData];
}
if ([syncArray count]==0) {
return nil;
}

return syncArray;
}

4. 从数据库中取数据,封装成对象,然后放入数组中

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

在数据量很大时候,考虑到性能问题,此方法需要酌情使用。

好了,最后提供这四个文件DbHelper.h、DbHelper.m、NSObject+Property.h、NSObject+Property.m的下载。
有了这几个东西,进行开发就省去了很多时间和代码量,直接动态生成表,从服务端接口取到数据,直接插入到数据库中保存,显示数据时,从数据库中取出数据放入到对象数组中。

由于项目的保密性,不可能提供整个文件的下载,只提供了关键的几个文件,同学们可以根据需要进行扩展和研究,也欢迎一起探讨,甚至拍砖。

文件下载:http://pan.baidu.com/share/link?shareid=202843&uk=85241834

时间: 2024-11-02 20:12:45

ios反射的相关文章

iOS反射机制: objc_property_t的使用

iOS属性反射:说白了,就是将两个对象的所有属性,用动态的方式取出来,并根据属性名,自动绑值.(注意:对象的类,如果是派生类,就得靠其他方式来实现了,因为得到不该基类的属性.) 常用的反射方式,有如下两种: 从一个自定义实体类->自定义实体类 从一个NSDictionary->自定义实体类(此方式最最常用,如网络Json数据会组成NSDictionary.sqlite查询数据,可以用第三方组件组成NSDictionary)直接上码,(这里码在NSObject类别中)获取对象所有属性:- (NS

ios 反射,MVC之model

mvc模式大家都很清楚了!最大的好处就是条理清晰一点,view和数据分开,在viewController中只要处理view和数据的逻辑就好了,甚至于逻辑都在model中处理,嗯想说什么呢,过去两个礼拜吧,都在做一件很挫的事情:model都是这样子写的: @interface SPExangeModel : NSObject /*! * 模型属性 */ @property (nonatomic, copy) NSString * city; @property (nonatomic, copy)

ios 反射机制

// Created  By   郭仔  2015年04月11日17:13:22 NSObject常用方法: ======================================================================= OC反射机制:

iOS 反射函数: performSelector 和 NSInvocation

当我们有方法名和参数列表,想要动态地给对象发送消息,可用通过反射函数机制来实现,有两种常用的做法: 一.performSelector 1 - (id)performSelector:(SEL)aSelector; 2 - (id)performSelector:(SEL)aSelector withObject:(id)object; 3 - (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)obj

IOS反射机制的几个重要函数

/* object-c的语法学习 main.mm made by davidsu33 -(BOOL)isKindOfClass: classObj 是否是其子孙或一员 -(BOOL)isMemberOfClass: classObj 是否是其一员 -(BOOL)respondsToSelector: selector 是否有这种方法 +(BOOL)instancesRespondToSelector: selector 类的对象是否有这种方法 -(id)performSelector: sele

iOS 反射获取类的属性列表

// 获取对象所有属性: - (NSArray*)propertyKeys { unsigned int outCount, i; objc_property_t *properties = class_copyPropertyList([self class], &outCount); NSMutableArray *keys = [[NSMutableArray alloc] initWithCapacity:outCount]; for (i = 0; i < outCount; i+

【iOS开发系列】用简单工厂模式理解OC反射机制

// 在iOS开发中,简单工厂模式使用得并不多.但是.我认为这是OC反射机制很好的一个例子, // 所以本文将以计算器为例,讲解简单工厂模式和OC的反射机制. // [简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类( // 这些产品类继承自一个父类或接口)的实例.该模式中包含的角色及其职责:工厂角色.抽 // 象产品角色.具体产品角色] // --百度百科 简单工厂模式 // 上面这句话可能不怎么好理解,我在网上找到了一个例子,可能例子本身不能完全解释这个 // 设

iOS运行时编程(Runtime Programming)和Java的反射机制对比

运行时进行编程,类似Java的反射.运行时编程和Java反射的对比如下: 1.相同点 都可以实现的功能:获取类信息.属性设置获取.类的动态加载(NSClassFromString(@“className”)).方法的动态调用 下面是iOS中涉及到的相关使用方法 类的动态加载:NSClassFromString(@“className”),方法的动态调用:NSSelectorFormString(@”doSonethingMethod:”) 常见的方法: isKindOfClass: isMemb

【IOS 开发】Object - C 面向对象高级特性 - 包装类 | 类处理 | 类别 | 扩展 | 协议 | 委托 | 异常处理 | 反射

一. Object-C 对象简单处理 1. 包装类 (1) 包装类简介 NSValue 和 NSNumber : -- 通用包装类 NSValue : NSValue 包装单个 short, int, long, float, char, id, 指针 等数据; -- NSNumber 包装类 : 用于包装 C 语言数据类型; NSNumber 方法 : -- "+ numberWithXxx :" : 将特定类型的值包装成 NSNumber; -- "- initWithX