预告 ARC 重写:iOS 实现的 json 数据源的 O-R Mapping

简介: iOS 实现的 json 数据源的 O-R Mapping太阳火神的美丽人生 (http://blog.csdn.net/opengl_es)本文遵循“署名-非商业用途-保持一致”创作公用协议转载请保留此句:太阳火神的美丽人生 -  本博客专注于 敏捷开发及移动和物联设备研究:iOS、Android、Html5、Arduino、pcDuino,否则,出自本博客的文章拒绝转载或再转载,谢谢合作。

iOS 实现的 json 数据源的 O-R Mapping

太阳火神的美丽人生 (http://blog.csdn.net/opengl_es)

本文遵循“署名-非商业用途-保持一致”创作公用协议

转载请保留此句:太阳火神的美丽人生 -  本博客专注于 敏捷开发及移动和物联设备研究:iOS、Android、Html5、Arduino、pcDuino否则,出自本博客的文章拒绝转载或再转载,谢谢合作。



时隔几年之久,再来看这四天写出的成果,不禁对那时的自已心生敬佩。

想来,现在看这堆风格很合理的代码,也有些难度,

因为,其中有几个 OC 的类继承的点,是不能用常规面向对象继承来理解的,

而是借鉴 Linux 底层中 C 语言实现的对象机制,逐层提取完成。

确实这一部分当时费了很多脑汁!


当时用 MRC 写成,现在 ARC 已经基本取代了 MRC,而 Swift 在今年的稍晚些时侯,也会取代 ARC 成为常规编程语言而应用于实际项目开发中,

所以,在 ARC 尚在的时侯,把这一课补上吧,别留下遗憾,真正开始了 Swift 的时侯,就不会再有心力和驱动力去使用 ARC 了。!#)*$&#^^*


本处仅为预告,至少是否真得能够重写,还看机缘吧。 

------------------------


再挖个坑,这个相对复杂一些,当时花了四天时间,在2010年的时侯,对于Objective-C 的反射机制的研究。

其中的设计思想,大多源自 Android 教父高焕堂先生的基类架构思想,我这里只是取了其中一小点点,拿到iOS上用一用。

曾经参加过高焕堂先生在我们公司讲授的近一个月的Android课程,Android上来说学到什么,都是次要的,最重要的是在架构设计思想上得到了真经。

高焕堂:台湾Android论坛主席,现任亚太地区Android技术大会主席,台湾Android领域框架开发联盟总架构师。发表100多篇Android核心技术文章,出版了6本Android专业技术书籍。专精于Android 核心框架及核心服务程序开发。


以下仅为相关核心类部分,涉及业务逻辑部分均已删除,不便透露。

其它实体类从该基类派生,各子类成员需有如下限定:

 1实体必须继承自BaseEntity,且该实体类成员变量只能是如下类型的对象:

 NSString

 NSNumber

 NSDecimalNumber

 UIImage

 NSArray

 BaseEntity的子类

  2不允许使用NSDictionary,如确需要,可考虑定义对应实体类,且该实体类必须继承自BaseEntity

  3禁止有继承关系的类进行复合、聚集。

        任何循环引用的情况均需考虑是否会造成解析死循环,比如,a对象有一个数组成员,那么该数组的元素不能是a对象及其子类;

  4

       a、数组元素值为NSNull,用空字符串代替

       b、成员变量值为nil,解析会自动忽略该成员

       c、未在 中列出的类及其子类,解析会自动忽略

 

 // 以下类型转成json均协同测试通过

 数值:NSNumber

 整型

 长整型:最多传入10位数字,超过则溢出显示成负数

 单精度

 双精度

 布尔

 日期:NSDate

 字符串:NSString

 图片:UIImage

 数组:NSArray

 对象:BaseEntity的子类


@interface BaseEntity(Private)
//图片base64编解码方法
- (NSString *)encodeToBase64:(NSData *)toEncodeData;
- (NSData *)decodeFromBase64:(NSString *)toDecodeString;
- (NSString *)encodeUIImageToBase64:(UIImage *)toEncodeUIImage;
- (UIImage *)decodeUIImageFromBase64:(NSString *)toDecodeString;
//实体映射到键值
- (NSString *)parseAttributeType:(NSString *)Attributes;
- (NSArray *)getClassPropertys:(Class)classInstance;
- (NSArray *)getAllPropertys:(Class)classInstance;
- (NSDictionary *)getAllClassMapping:(Class)classInstance;
- (NSArray *)getPropertyList;
- (NSDictionary *)getClassMapping;
//键值映射到json
- (NSString *)generateRandomNumber;
- (NSArray *)getArrayContainSubedClass:(NSArray *)dealedArray;
- (NSDictionary *)getDictionaryContainedSubClass;
@end


@implementation BaseEntity


#pragma mark - 类生命周期

- (id)init
{
    self = [super init];
    if (self) {
        
    }
    
    return self;
}

- (void)dealloc {
    
    [super dealloc];
}


#pragma mark - 类属性映射表:各子如需替换json中的键值名,实现该方法

+ (NSDictionary *)getMappingDic {
    
    return [NSDictionary dictionaryWithObjectsAndKeys:@"tokenid", @"token", nil];
}

+ (NSDictionary *)dictionaryPresentationOf:(NSString *)className {
    
    Class subClass = NSClassFromString(className);
    BaseEntity *baseEntity = [[subClass alloc] init];
    NSDictionary *propertyDic = [NSDictionary dictionaryWithDictionary:[baseEntity dictionaryPresentation]];
    [baseEntity release];
    
    return propertyDic;
}

+ (NSString *)JSONRepresentationOf:(NSString *)className {
    
    Class subClass = NSClassFromString(className);
    BaseEntity *baseEntity = [[subClass alloc] init];
    NSString *jsonString = [NSString stringWithString:[baseEntity JSONRepresentation]];
    [baseEntity release];
    
    return jsonString;
}


#pragma mark - 图片base64编解码方法

- (NSString *)encodeToBase64:(NSData *)toEncodeData {
    
    NSUInteger shouldLength = ([toEncodeData length] + 2) / 3 * 3;
    NSUInteger base64Length = shouldLength / 3 * 4 + 1;
    
    char *base64Bytes = malloc(base64Length);
    memset(base64Bytes, 0, base64Length);
    
    encodeBase64([toEncodeData bytes], [toEncodeData length], base64Bytes, &base64Length);
    
    NSString *base64String = [[[NSString alloc] initWithUTF8String:base64Bytes] autorelease];
    
    return base64String;
}

- (NSData *)decodeFromBase64:(NSString *)toDecodeString {
    
    return nil;
}

- (NSString *)encodeUIImageToBase64:(UIImage *)toEncodeUIImage {
    NSData *imageData = UIImagePNGRepresentation(toEncodeUIImage);
    return [self encodeToBase64:imageData];
}

- (UIImage *)decodeUIImageFromBase64:(NSString *)toDecodeString {
    return nil;
}


#pragma mark - 实体映射到键值

- (NSString *)parseAttributeType:(NSString *)Attributes {
    NSRange leftRange = [Attributes rangeOfString:@"\""];
    NSString *temp1 = [Attributes substringFromIndex:leftRange.location+1];
    NSRange rightRange = [temp1 rangeOfString:@"\""];
    NSString *temp2 = [temp1 substringToIndex:rightRange.location];
    
    return temp2;
}

// 获取某个类自身的所有属性
- (NSArray *)getClassPropertys:(Class)classInstance {
    NSMutableArray *classPropertyDics = [[NSMutableArray alloc] init];
    
    u_int count;
    objc_property_t *properties  = class_copyPropertyList(classInstance, &count);
    for (int i = 0; i < count ; i++) {
        const char* propertyName = property_getName(properties[i]);
        const char* propertyAttributes = property_getAttributes(properties[i]);
        NSString *name = [NSString stringWithUTF8String:propertyName];
        NSString *attribute = [NSString stringWithUTF8String:propertyAttributes];
        NSString *attributeType = [self parseAttributeType:attribute];
        
        NSMutableDictionary *propertyDic = [[NSMutableDictionary alloc] init];
        [propertyDic setObject:attributeType forKey:name];
        [classPropertyDics insertObject:propertyDic atIndex:0];
        //[propertys addObject: propertyDic];
        [propertyDic release];
    }
    free(properties);
    
    return (NSArray *)classPropertyDics;
}

// 递归获取该类至其某一层父层(参数指定)的所有类的属性集合
- (NSArray *)getAllPropertys:(Class)classInstance {
    NSMutableArray *allPropertys = [[[NSMutableArray alloc] init] autorelease];
    
    if (![[[[[classInstance superclass] alloc] init] autorelease] isMemberOfClass:[BaseEntity class]]) {
        NSArray *superPropertys = [self getAllPropertys:[classInstance superclass]];
        [allPropertys addObjectsFromArray:superPropertys];
    }
    
    NSArray *propertys = [self getClassPropertys:classInstance];
    [allPropertys addObjectsFromArray:propertys];
    
    return allPropertys;
}

- (NSDictionary *)getAllClassMapping:(Class)classInstance {
    NSMutableDictionary *allMappingDic = [[[NSMutableDictionary alloc] init] autorelease];
    
    if (![[[[[classInstance superclass] alloc] init] autorelease] isMemberOfClass:[BaseEntity class]]) {
        NSDictionary *mappingDic = [self getAllClassMapping:[classInstance superclass]];
        NSArray *keys = [mappingDic allKeys];
        for (NSString *key in keys) {
            NSString *value = [mappingDic objectForKey:key];
            [allMappingDic setObject:value forKey:key];
        }
    }
    
    
    NSDictionary *classMappingDic = (NSDictionary *)[classInstance getMappingDic];
    NSArray *keys = [classMappingDic allKeys];
    for (NSString *key in keys) {
        NSString *value = [classMappingDic objectForKey:key];
        [allMappingDic setObject:value forKey:key];
    }
    
    return allMappingDic;
}

- (NSArray *)getPropertyList {
    NSArray *propertys = [self getAllPropertys:[self class]];
    
    return propertys;
}

- (NSDictionary *)getClassMapping {
    NSDictionary *mappingDic = [self getAllClassMapping:[self class]];
    
    return mappingDic;
}


#pragma mark - 键值映射到json

- (NSArray *)getArrayContainSubedClass:(NSArray *)dealedArray {
    NSMutableArray *outArray = [[[NSMutableArray alloc] init] autorelease];
    
    for (id element in dealedArray) {
        if (NO == [element isKindOfClass:[NSNull class]]) {
            //字符串
            if (YES == [element isKindOfClass:[NSString class]]) {
                [outArray addObject:element];
            }
            //数值
            else if (YES == [element isKindOfClass:[NSNumber class]]) {
                [outArray addObject:element];
            }
            //浮点型:暂未用,仅json转成对象时,浮点型会转成此类型
            else if (YES == [element isKindOfClass:[NSDecimalNumber class]]) {
                [outArray addObject:element];
            }
            //日期
            else if (YES == [element isKindOfClass:[NSDate class]]) {
                NSDate *attributeDateValue = (NSDate *)element;
                double attributeDoubleValue = [attributeDateValue timeIntervalSince1970];
                NSMutableDictionary *specialDic = [[NSMutableDictionary alloc] init];
                [specialDic setObject:[NSNumber numberWithLongLong:attributeDoubleValue] forKey:@"time"];
                [specialDic setObject:@"java.util.Date" forKey:@"javaClass"];
                [outArray addObject:specialDic];
                [specialDic release];
            }
            //图片
            else if (YES == [element isKindOfClass:[UIImage class]]) {
                NSString *base64String = [self encodeUIImageToBase64:(UIImage *)element];
                [outArray addObject:base64String];
            }
            //数组
            else if (YES == [element isKindOfClass:[NSArray class]]) {
                NSArray *dealedArray = [self getArrayContainSubedClass:(NSArray *)element];
                [outArray addObject:dealedArray];
            }
            //BaseEntity的子类
            else if (YES == [element isKindOfClass:[BaseEntity class]]) {
                NSDictionary *objDic = [element getDictionaryContainedSubClass];
                [outArray addObject:objDic];
            }
            else {
                //非以上类型的成员,此忽略,并提示开发人员,成员填写需进一步核实
                NSLog(@"忽略并且未转换成json的数组元素:%@", element);
            }
        }
        else {
            [outArray addObject:@""];
        }
    }
    
    return outArray;
}

- (NSDictionary *)getDictionaryContainedSubClass {
    NSArray *propertys = [self getPropertyList];
    NSDictionary *mappingDic = [self getClassMapping];
    
    NSMutableDictionary *selfDic = [[[NSMutableDictionary alloc] init] autorelease];
    for (NSDictionary *elementDic in propertys) {
        NSArray *keys = [elementDic allKeys];
        //正常来说,该层循环只有一次,特别情况例外(特别情况暂未知,留此接口)
        for (NSString *attributeName in keys) {
            //映射
            NSString *mappingKeyName = [mappingDic objectForKey:attributeName];
            if (nil == mappingKeyName) {
                mappingKeyName = attributeName;
            }
            
            id attributeValue = [self valueForKey:attributeName];
            if (nil != attributeValue) {
                //字符串
                if (YES == [attributeValue isKindOfClass:[NSString class]]) {
                    [selfDic setObject:attributeValue forKey:mappingKeyName];
                }
                //数值
                else if (YES == [attributeValue isKindOfClass:[NSNumber class]]) {
                    [selfDic setObject:attributeValue forKey:mappingKeyName];
                }
                //浮点型:暂未用,仅json转成对象时,浮点型会转成此类型
                else if (YES == [attributeValue isKindOfClass:[NSDecimalNumber class]]) {
                    [selfDic setObject:attributeValue forKey:mappingKeyName];
                }
                //日期
                else if (YES == [attributeValue isKindOfClass:[NSDate class]]) {
                    NSDate *attributeDateValue = (NSDate *)attributeValue;
                    double attributeDoubleValue = [attributeDateValue timeIntervalSince1970];
                    NSMutableDictionary *specialDic = [[NSMutableDictionary alloc] init];
                    [specialDic setObject:[NSNumber numberWithLong:attributeDoubleValue] forKey:@"time"];
                    [specialDic setObject:@"java.util.Date" forKey:@"javaClass"];
                    [selfDic setObject:specialDic forKey:mappingKeyName];
                    [specialDic release];
                }
                //图片
                else if (YES == [attributeValue isKindOfClass:[UIImage class]]) {
                    NSString *base64String = [self encodeUIImageToBase64:(UIImage *)attributeValue];
                    [selfDic setObject:base64String forKey:mappingKeyName];
                }
                //数组
                else if (YES == [attributeValue isKindOfClass:[NSArray class]]) {
                    NSArray *outArray = [self getArrayContainSubedClass:(NSArray *)attributeValue];
                    [selfDic setObject:outArray forKey:mappingKeyName];
                }
                //BaseEntity的子类
                else if (YES == [attributeValue isKindOfClass:[BaseEntity class]]) {
                    NSDictionary *objDic = [attributeValue getDictionaryContainedSubClass];
                    [selfDic setObject:objDic forKey:mappingKeyName];
                }
                else {
                    //非以上类型的成员,此忽略,并提示开发人员,成员填写需进一步核实
                    NSLog(@"忽略并且未转换成json的成员:%@", attributeName);
                }
            }
            else {
                [selfDic setObject:@"" forKey:mappingKeyName];
            }
        }
    }
    return selfDic;
}

- (NSDictionary *)dictionaryPresentation {
    return [self getDictionaryContainedSubClass];
}

- (NSString *)JSONRepresentation {
    NSDictionary *dictionaryPresentationDic = [self dictionaryPresentation];
    if ([dictionaryPresentationDic respondsToSelector:@selector(JSONRepresentation)]) {
        return [dictionaryPresentationDic JSONRepresentation];
    }
    else {
        return nil;
    }
}

- (NSString *)generateUuidString {
    CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
    NSString *uuidString = (NSString*)CFUUIDCreateString(kCFAllocatorDefault, uuid);
    [uuidString autorelease];
    CFRelease(uuid);
    return uuidString;
}

//按业务实际要求提供随机数算法,本处仅简单使用c语言随机数生成
- (NSString *)generateRandomNumber {
    int value = (arc4random() % 1000000000) + 1;
    
    return [NSString stringWithFormat:@"%d", value];
}

- (NSDictionary *)dictionaryPresentation:(NSString *)method {
    if (nil != method) {
        NSDictionary *businessDic = [self getDictionaryContainedSubClass];
        NSString *randomString = [self generateRandomNumber];
        
        NSMutableDictionary *resultDic = [[[NSMutableDictionary alloc] init] autorelease];
        [resultDic setObject:randomString forKey:@"id"];
        [resultDic setObject:method forKey:@"method"];
        NSArray *params = [NSArray arrayWithObject:businessDic];
        [resultDic setObject:params forKey:@"params"];
        
        return resultDic;
    }
    else {
        return nil;
    }
}

- (NSString *)JSONRepresentation:(NSString *)method {
    NSDictionary *dictionaryPresentationDic = [self dictionaryPresentation:method];
    if ([dictionaryPresentationDic respondsToSelector:@selector(JSONRepresentation)]) {
        return [dictionaryPresentationDic JSONRepresentation];
    }
    else {
        return nil;
    }
}

- (NSData *)JSONDataRepresentation:(NSString *)method {
    NSString *resultJsonString = [self JSONRepresentation:method];
    
    return (NSData *)[NSData dataWithBytes:[resultJsonString UTF8String] length:[resultJsonString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]];
}

@end


此类是在我马上要出差去北京之前的四天时间里怱忙写成,费了不少脑汁,而且还费了不少口水说服小鬼儿们使用,不过还是得益于严大神的全力支持,感谢感谢再感谢,感谢在这里工作期间,大神对我的关照和支持,别人都觉得您出差不在家了,不用提心吊胆了,真爽!我听到您不在家去差了,心情正好想反,觉得您不在家了,就好像缺点儿什么似的,只要看着您在,我默默地工作,都觉得有底,再难的问题,都觉得能解决,因为即使我解决不了,还有您给指点。

现在每每行事,遇到难题,都会回想起,您当时处事的风格,宽容、大度、淡然、从容、果断、重情义......,随便挑出几样照着做,总会有豁然开朗的心情陪伴,虽然我不愿意也不可能再回去,但总还是忘不了您这位伯乐。

哈哈哈,看官们,上面这段话,也许你们看不懂,但绝对能让我回忆起那段快乐、轻松的时光,也就是在那里,我从战术型思维转入战略型思维,这是过后一些还在那里工作的兄弟们给的评价,慢慢自已发现好像是有这样的变化。

人得学会感恩,因为你感恩,所以你能够拥抱一切,因为你乐于感恩,所以一切也会拥抱你。


目录
相关文章
|
3月前
|
Swift iOS开发 开发者
IOS开发基础知识:什么是 ARC(自动引用计数)?如何工作?
IOS开发基础知识:什么是 ARC(自动引用计数)?如何工作?
43 1
|
安全 数据安全/隐私保护 iOS开发
iOS小技能:【发红包】使用tweak和lua脚本结合进行实现
我们开发的大部分越狱程序,都是编译成动态链接库(`例如:介绍的越狱程序(Tweak)开发,就是动态链接库。`),然后通过越狱平台的MobileSubstrate(iOS7上叫CydiaSubstrate)来加载进入目标程序(Target),通过对目标程序的挂钩(Hook),来实现相应的功能。
262 0
|
11月前
|
JSON 数据格式 iOS开发
iOS基础 JSON格式
iOS基础 JSON格式
97 0
|
11月前
|
JSON 移动开发 数据格式
iOS url传递JSON格式参数方法
iOS url传递JSON格式参数方法
215 0
|
移动开发 JavaScript weex
weex-自定义module,实现weex在iOS的本地化,js之间互相跳转,交互,传值(iOS接入weex的最佳方式)
weex-自定义module,实现weex在iOS的本地化,js之间互相跳转,交互,传值(iOS接入weex的最佳方式)
219 0
|
存储 数据处理 iOS开发
iOS开发-本地推送实现方法和数据处理方案(二)
iOS开发-本地推送实现方法和数据处理方案(二)
167 0
|
存储 数据处理 iOS开发
iOS开发-本地推送实现方法和数据处理方案(一)
iOS开发-本地推送实现方法和数据处理方案(一)
208 0
|
iOS开发
iOS开发 - 不通过import引入类名实现push或present
iOS开发 - 不通过import引入类名实现push或present
75 0
|
Android开发 iOS开发
iOS开发 - 商品详情页两种分页模式,只提供思路和实现方式。
iOS开发 - 商品详情页两种分页模式,只提供思路和实现方式。
354 0
iOS开发 - 商品详情页两种分页模式,只提供思路和实现方式。
|
存储 安全 iOS开发
iOS开发 - 继udid,Mac地址等一系列唯一标识无效后,如何用KeyChain来实现设备唯一性
iOS开发 - 继udid,Mac地址等一系列唯一标识无效后,如何用KeyChain来实现设备唯一性
397 0
iOS开发 - 继udid,Mac地址等一系列唯一标识无效后,如何用KeyChain来实现设备唯一性