你好,歡迎來到IOS教程網

 Ios教程網 >> IOS訊息 >> 關於IOS >> iOS反射

iOS反射

編輯:關於IOS

移動互聯網下iOS客戶端的開發,一般都會與服務端進行通訊,也會使用到Sqlite數據庫來保存一些數據,按常規的搞法,一般都需要手動建表結構,寫實體類對象,然後寫插入、更新、查詢等語句來實現功能,因此想到是否有一種通用的辦法來進行一些代碼方面的減負工作。利用反射的機制,可以很方便的實現。

首先,我們進行了以下的約定:

sqlite的數據庫表名直接使用實體類的類名;
sqlite的數據字段使用實體類的屬性名稱;
sqlite的數據類型統一設為text(引起sqlite這種文本數據庫是動態類型的,存儲的本質都是文本)
實體類的類型統一都設為NSString
做以上的約定,只是減少使用過程中,由於類型的不同造成不必要的麻煩,如果要支持各種類型,需要編寫各種判斷代碼,進行格式的處理,有興趣的同學可以進一步研究。

先擴展了NSObject,名稱叫NSObject+Property,然後添加下面代碼。

利用反射取得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;
}

根據屬性生成創建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;
}

把一個實體對象,封裝成字典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;
}
從一個字典中還原成一個實體對象

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

返回一個對象的類型名稱

- (NSString *)className
{
return [NSString stringWithUTF8String:object_getClassName(self)];
}

以上是對NSObject的一個擴展,使用了Obj-C的Category特性

以下是與數據存儲相關,定義為DbHelper,對sqlite進行操作

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

把字典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];
}];
}
}

取數據

從數據庫取數據,封裝成成字典,然後放入到數組中

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

從數據庫中取數據,封裝成對象,然後放入數組中

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

在數據量很大時候,考慮到性能問題,此方法需要酌情使用。

有了這幾個東西,進行開發就省去了很多時間和代碼量,直接動態生成表,從服務端接口取到數據,直接插入到數據庫中保存,顯示數據時,從數據庫中取出數據放入到對象數組中。

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved