// // NSObject+LHModel.m // LHDBDemo // // Created by 3wchina01 on 16/3/21. // Copyright © 2016年 李浩. All rights reserved. // #import "NSObject+LHModel.h" #import "LHObjectInfo.h" #import #import #import @implementation NSObject (LHModel) static void ModelSetValueToProperty(const void *key, const void *value, void *context) { ModelSetContext* modelContext = context; NSString* dicKey = (__bridge NSString *)(key); id dicValue = (__bridge id)(value); LHObjectInfo* objectInfo = [((__bridge LHClassInfo*)modelContext->classInfo) objectInfoWithName:dicKey]; NSObject* object = (__bridge NSObject*)modelContext->model; if (objectInfo) { if (objectInfo.cls) { setNSTypePropertyValue(object, dicValue, objectInfo.nsTypeEcoding, objectInfo.set); }else if (objectInfo.type.length>0) { NSNumber* number = numberWithValue(dicValue); setBaseTypePropertyValue(object, number, objectInfo.baseTypeEcoding,objectInfo.set); } } } static void ModelGetValueToDic(const void* key,const void* value,void* context) { ModelSetContext* modelContext = context; NSMutableDictionary* dic = (__bridge NSMutableDictionary *)(modelContext->classInfo); id object = (__bridge id)(modelContext->model); NSString* dicKey = (__bridge NSString *)(key); LHObjectInfo* objectInfo = (__bridge LHObjectInfo*)(value); if (objectInfo) { if (objectInfo.cls) { [dic setValue:((id(*)(id,SEL))(void*) objc_msgSend)(object,objectInfo.get) forKey:dicKey];; }else if (objectInfo.type.length>0) { NSNumber* number = getBaseTypePropertyValue(object, objectInfo.baseTypeEcoding, objectInfo.get); [dic setValue:number forKey:dicKey]; } } } static NSNumber* numberWithValue(__unsafe_unretained id value) { if (!value) { return nil; } if ([value isKindOfClass:[NSNumber class]]) return value; if ([value isKindOfClass:[NSString class]]) { if ([value containsString:@"."]) { const char *cstring = ((NSString *)value).UTF8String; if (!cstring) return nil; double num = atof(cstring); if (isnan(num) || isinf(num)) return nil; return @(num); }else { const char *cstring = ((NSString*)value).UTF8String; if (!cstring) return nil; NSNumber* number = @(atoll(cstring)); if (!atoll(cstring)) { number = [NSNumber numberWithChar:*(cstring+0)]; } return number; } } return nil; } static void setBaseTypePropertyValue(__unsafe_unretained NSObject* object,__unsafe_unretained NSNumber* value, NSUInteger type,SEL set) { switch (type) { case LHBaseTypeEcodingINT: ((void (*)(id, SEL, int))(void *) objc_msgSend)(object, set, value.intValue); break; case LHBaseTypeEcodingLONG: ((void(*)(id,SEL,long))(void*) objc_msgSend)(object,set,value.integerValue); break; case LHBaseTypeEcodingULONG: ((void(*)(id,SEL,long))(void*) objc_msgSend)(object,set,value.unsignedIntegerValue); break; case LHBaseTypeEcodingFLOAT: ((void(*)(id,SEL,float))(void*) objc_msgSend)(object,set,value.floatValue); break; case LHBaseTypeEcodingDOUBLE: ((void(*)(id,SEL,double))(void*) objc_msgSend)(object,set,value.doubleValue); break; case LHBaseTypeEcodingBOOL: ((void(*)(id,SEL,BOOL))(void*) objc_msgSend)(object,set,value.boolValue); break; case LHBaseTypeEcodingCHAR: ((void(*)(id,SEL,char))(void*) objc_msgSend)(object,set,value.charValue); break; default: ((void(*)(id,SEL,id))(void*) objc_msgSend)(object,set,nil); break; } } static void setNSTypePropertyValue(__unsafe_unretained id object,__unsafe_unretained id value,LHNSTypeEcoding typeEcoding,SEL set) { switch (typeEcoding) { case LHNSTypeUNknow: ((void(*)(id,SEL,id))(void*) objc_msgSend)(object,set,value); break; case LHNSTypeNSString: if ([value isKindOfClass:[NSString class]]) { ((void(*)(id,SEL,id))(void*) objc_msgSend)(object,set,value); }else if ([value isKindOfClass:[NSNumber class]]) { ((void(*)(id,SEL,id))(void*) objc_msgSend)(object,set,[value stringValue]); }else if ([value isKindOfClass:[NSData class]]) { ((void(*)(id,SEL,id))(void*) objc_msgSend)(object,set,[[NSString alloc] initWithData:value encoding:NSUTF8StringEncoding]); }else if ([value isKindOfClass:[NSDate class]]) { ((void(*)(id,SEL,NSString*))(void*) objc_msgSend)(object,set,stringFormDate(value)); }else ((void(*)(id,SEL,id))(void*) objc_msgSend)(object,set,value); break; case LHNSTypeNSNumber: ((void(*)(id,SEL,NSNumber*))(void*) objc_msgSend)(object,set,numberWithValue(value)); break; case LHNSTypeNSDate: if ([value isKindOfClass:[NSDate class]]) { ((void(*)(id,SEL,NSDate*))(void*) objc_msgSend)(object,set,value); }else if ([value isKindOfClass:[NSString class]]) { ((void(*)(id,SEL,NSDate*))(void*) objc_msgSend)(object,set,dateFromString(value)); }else if ([value isKindOfClass:[NSData class]]) { NSString* dateStr = [[NSString alloc] initWithData:value encoding:NSUTF8StringEncoding]; ((void(*)(id,SEL,NSDate*))(void*) objc_msgSend)(object,set,dateFromString(dateStr)); }else ((void(*)(id,SEL,id))(void*) objc_msgSend)(object,set,value); break; case LHNSTypeNSData: ((void(*)(id,SEL,NSData*))(void*) objc_msgSend)(object,set,dataFromObject(value)); break; case LHNSTypeNSURL: ((void(*)(id,SEL,NSURL*))(void*) objc_msgSend)(object,set,urlFromObject(value)); break; case LHNSTypeNSArray: ((void(*)(id,SEL,NSArray*))(void*) objc_msgSend)(object,set,arrayFromObject(value)); break; case LHNSTypeNSDictionary: ((void(*)(id,SEL,NSDictionary*))(void*) objc_msgSend)(object,set,dicFromObject(value)); break; case LHNSTypeUIImage: ((void(*)(id,SEL,UIImage*))(void*) objc_msgSend)(object,set,imageFromObject(value)); break; default: break; } } static NSNumber* getBaseTypePropertyValue(__unsafe_unretained NSObject* object, NSUInteger type,SEL get) { switch (type) { case LHBaseTypeEcodingINT: return @(((int (*)(id, SEL))(void *) objc_msgSend)(object, get)); case LHBaseTypeEcodingLONG: return @(((long (*)(id, SEL))(void *) objc_msgSend)(object,get)); case LHBaseTypeEcodingULONG: return @(((NSUInteger(*)(id,SEL))(void*) objc_msgSend)(object,get)); case LHBaseTypeEcodingFLOAT: return @(((float(*)(id,SEL))(void*) objc_msgSend)(object,get)); case LHBaseTypeEcodingDOUBLE: return @(((double(*)(id,SEL))(void*) objc_msgSend)(object,get)); case LHBaseTypeEcodingBOOL: return @(((BOOL(*)(id,SEL))(void*) objc_msgSend)(object,get)); case LHBaseTypeEcodingCHAR: return @(((char(*)(id,SEL))(void*) objc_msgSend)(object,get)); default: return nil; break; } } typedef struct { void *classInfo; void *model; } ModelSetContext; + (id)lh_ModelWithJSON:(id)json { if (!json) return nil; if ([json isKindOfClass:[NSDictionary class]]) { return [self lh_ModelWithDictionary:(NSDictionary*)json]; } NSData* jsonData; if ([json isKindOfClass:[NSString class]]) { jsonData = [(NSString*)json dataUsingEncoding:NSUTF8StringEncoding]; }else if ([json isKindOfClass:[NSData class]]) jsonData = json; if (jsonData) { return [self lh_ModelWithDictionary:[NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:nil]]; } return nil; } + (id)lh_ModelWithDictionary:(NSDictionary*)dic { if (!dic ||![dic isKindOfClass:[NSDictionary class]]) return nil; NSObject* object = [[self alloc] init]; ModelSetContext context = {0}; LHClassInfo* info; //判断缓存中是否有这个类的信息 if ([LHClassInfo isCacheWithClass:self]) { info = [LHClassInfo classInfoWithClass:self]; }else info = [[LHClassInfo alloc] initWithClass:self]; context.classInfo = (__bridge void *)(info); context.model = (__bridge void *)(object); CFDictionaryApplyFunction((__bridge CFDictionaryRef)dic, ModelSetValueToProperty, &context); return object; } - (NSDictionary*)lh_ModelToDictionary { if ([self isKindOfClass:[NSArray class]]) { return nil; }else if ([self isKindOfClass:[NSDictionary class]]){ return (NSDictionary*)self; }else if ([self isKindOfClass:[NSString class]]||[self isKindOfClass:[NSData class]]) { return [NSJSONSerialization JSONObjectWithData:dataFromObject(self) options:NSJSONReadingMutableContainers error:nil]; }else { NSMutableDictionary* dic = [NSMutableDictionary dictionary]; ModelSetContext context = {0}; context.classInfo = (__bridge void *)(dic); context.model = (__bridge void *)(self); LHClassInfo* classInfo; //判断缓存中是否有这个类的信息 if ([LHClassInfo isCacheWithClass:object_getClass(self)]) { classInfo = [LHClassInfo classInfoWithClass:object_getClass(self)]; }else classInfo = [[LHClassInfo alloc] initWithClass:object_getClass(self)]; CFDictionaryApplyFunction((__bridge CFMutableDictionaryRef)classInfo.objectInfoDic, ModelGetValueToDic, &context); return dic; } return nil; } - (NSData*)lh_ModelToData { return [NSJSONSerialization dataWithJSONObject:[self lh_ModelToDictionary] options:NSJSONWritingPrettyPrinted error:nil];; } + (NSDictionary*)getAllPropertyNameAndType { NSMutableDictionary* dic = [NSMutableDictionary dictionary]; unsigned int count = 0; objc_property_t* property_t = class_copyPropertyList(self, &count); for (int i=0; i= 1) { return strArray[1]; }else return nil; }else return [typeString substringWithRange:NSMakeRange(1, 1)]; } static NSString* stringFormDate(NSDate* date) { NSDateFormatter* formatter = [[NSDateFormatter alloc] init]; formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss"; return [formatter stringFromDate:date]; } static NSDate* dateFromString(NSString* string) { NSDateFormatter* formatter = [[NSDateFormatter alloc] init]; formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss"; return [formatter dateFromString:string]; } static NSData* dataFromObject(id object) { if ([object isKindOfClass:[NSData class]]) { return object; }else if ([object isKindOfClass:[NSString class]]) { return [object dataUsingEncoding:NSUTF8StringEncoding]; }else if ([object isKindOfClass:[NSDate class]]) { return [stringFormDate(object) dataUsingEncoding:NSUTF8StringEncoding]; }else if ([object isKindOfClass:[NSArray class]]||[object isKindOfClass:[NSDictionary class]]) { return [NSJSONSerialization dataWithJSONObject:object options:NSJSONWritingPrettyPrinted error:nil]; }else if ([object isKindOfClass:NSClassFromString(@"UIImage")]) { return UIImageJPEGRepresentation(object, 1); }else return [object dataUsingEncoding:NSUTF8StringEncoding]; } static NSURL* urlFromObject(id object) { if ([object isKindOfClass:[NSURL class]]) { return object; }else if ([object isKindOfClass:[NSString class]]) { return [NSURL URLWithString:[object stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; }else { return [NSURL URLWithString:[[[NSString alloc] initWithData:dataFromObject(object) encoding:NSUTF8StringEncoding] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; } } static NSArray* arrayFromObject(id object) { if ([object isKindOfClass:[NSArray class]]) { return object; }else if ([object isKindOfClass:[NSDictionary class]]){ return nil; }else { id value = [NSJSONSerialization JSONObjectWithData:dataFromObject(object) options:NSJSONReadingMutableContainers error:nil]; if ([value isKindOfClass:[NSArray class]]) { return value; } return nil; } } static NSDictionary* dicFromObject(id object) { if ([object isKindOfClass:[NSDictionary class]]) { return object; }else { NSData* data = dataFromObject(object); id value = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil]; if ([value isKindOfClass:[NSDictionary class]]) { return value; } return nil; } } static UIImage* imageFromObject(id object) { if ([object isKindOfClass:[UIImage class]]) { return object; }else { return [UIImage imageWithData:dataFromObject(object)]; } } @end