iOS 实现的 json 数据源的 O-R Mapping
太阳火神的美丽人生 (http://blog.csdn.net/opengl_es)
本文遵循“署名-非商业用途-保持一致”创作公用协议
时隔几年之久,再来看这四天写出的成果,不禁对那时的自已心生敬佩。
想来,现在看这堆风格很合理的代码,也有些难度,
因为,其中有几个 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、未在 1 中列出的类及其子类,解析会自动忽略
// 以下类型转成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
现在每每行事,遇到难题,都会回想起,您当时处事的风格,宽容、大度、淡然、从容、果断、重情义......,随便挑出几样照着做,总会有豁然开朗的心情陪伴,虽然我不愿意也不可能再回去,但总还是忘不了您这位伯乐。
哈哈哈,看官们,上面这段话,也许你们看不懂,但绝对能让我回忆起那段快乐、轻松的时光,也就是在那里,我从战术型思维转入战略型思维,这是过后一些还在那里工作的兄弟们给的评价,慢慢自已发现好像是有这样的变化。
人得学会感恩,因为你感恩,所以你能够拥抱一切,因为你乐于感恩,所以一切也会拥抱你。