zoukankan      html  css  js  c++  java
  • ios反射

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

    1.反射获取类属性名和属性类型

    unsigned int propertyCount = 0;
        objc_property_t *properties = class_copyPropertyList([MyEntity class], &propertyCount);
        
        for (unsigned int i = 0; i < propertyCount; ++i) {
            objc_property_t property = properties[i];
            const char * name = property_getName(property);//获取属性名字
            const char * attributes = property_getAttributes(property);//获取属性类型
            NSLog(@"%@,%@", [NSString stringWithUTF8String:name], [NSString stringWithUTF8String:attributes]);
        }

    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) {
    columnValue=@"";
    }
    [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

  • 相关阅读:
    ASIHTTPREQUEST 文档
    本地通知
    ASIHttpRequest 使用过程中,中文编码的问题
    讲讲最近自己的学习,谈谈未来的想法
    关于 ASP.NET MVC 4 如果管理用户
    [转贴]超级懒汉编写的基于.NET的微信SDK
    [转贴]实践:C++平台迁移以及如何用C#做C++包装层
    [转贴]Linq之动态查询
    [转贴]watin的一些例子
    [转贴]xcode帮助文档
  • 原文地址:https://www.cnblogs.com/apem/p/4147005.html
Copyright © 2011-2022 走看看