123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- //
- // MAJsonUtils.m
- // amap_flutter_map
- //
- // Created by shaobin on 2019/2/13.
- // Copyright © 2019 Amap.com. All rights reserved.
- //
- #import "AMapJsonUtils.h"
- #import <objc/runtime.h>
- #import <objc/message.h>
- #import <CoreLocation/CoreLocation.h>
- #import "AMapConvertUtil.h"
- @implementation AMapJsonUtils
- + (BOOL)isValidJsonValue:(id)value {
- if([value isKindOfClass:NSString.class] ||
- [value isKindOfClass:NSNumber.class] ||
- value == [NSNull null]) {
- return YES;
- }
-
- return NO;
- }
- + (id)jsonValueFromObject:(id)obj {
- if([self isValidJsonValue:obj]) {
- return obj;
- }
-
- if(!obj) {
- return [NSNull null];
- }
-
- //常用基本类型判断,not exhausted
- if([obj isKindOfClass:NSDate.class] ||
- [obj isKindOfClass:NSData.class] ||
- [obj isKindOfClass:NSValue.class]) {
- NSString *retStr = [NSString stringWithFormat:@"%@", obj];
- return retStr;
- }
-
- if([obj isKindOfClass:NSArray.class]) {
- NSArray *oldArray = (NSArray*)obj;
- NSMutableArray *retArray = [NSMutableArray arrayWithCapacity:[oldArray count]];
- for(id item in oldArray) {
- id jsonValue = [self jsonValueFromObject:item];
- [retArray addObject:jsonValue];
- }
- return retArray;
- }
-
- if([obj isKindOfClass:NSDictionary.class]) {
- NSDictionary *oldDict = (NSDictionary *)obj;
- NSMutableDictionary *retDict = [NSMutableDictionary dictionaryWithCapacity:[oldDict count]];
- for(id key in [oldDict allKeys]) {
- id item = [oldDict objectForKey:key];
- id jsonValue = [self jsonValueFromObject:item];
- if(jsonValue) {
- [retDict setObject:jsonValue forKey:key];
- }
- }
- return retDict;
- }
-
- NSArray *propertyArray = [self allPropertiesOfClass:[obj class]];
- NSMutableDictionary *returnDict = [NSMutableDictionary dictionaryWithCapacity:propertyArray.count];
- for(NSString *property in propertyArray) {
- id value = [obj valueForKey:property];
- if(value) {
- id jsonValue = [self jsonValueFromObject:value];
- NSString *mappedName = property;
- if(jsonValue) {
- [returnDict setObject:jsonValue forKey:mappedName];
- }
- }
- }
- return returnDict;
- }
- + (id)jsonObjectFromModel:(id)model {
- id ret = [self jsonValueFromObject:model];
- if(![NSJSONSerialization isValidJSONObject:ret]) {
- return nil;
- }
-
- return ret;
- }
- + (id)modelFromDict:(NSDictionary*)dict modelClass:(Class)modelClass {
- if(![dict isKindOfClass:[NSDictionary class]]) {
- NSLog(@"[AMap] the object must be of %@", [NSDictionary class]);
- return nil;
- }
-
- if([modelClass isSubclassOfClass:[NSDictionary class]]) {
- return [dict copy];
- }
-
- //获取clazz属性列表
- NSArray *propertyArray = [self allPropertiesOfClass:modelClass];
- NSMutableArray* missedProperties = [NSMutableArray array];
- id ret = [[modelClass alloc] init];
- //枚举clazz中的每个属性,然后赋值
- for (NSString *propertyName in propertyArray) {
- NSString *keyName = propertyName;
- id value = [dict objectForKey:keyName];
- //'id'是关键字,服务端返回'id'字段属性名更改为'id_'
- if(!value && [propertyName isEqualToString:@"id_"]) {
- value = [dict objectForKey:@"id"];
- }
- if(!value) {
- [missedProperties addObject:propertyName];
- continue;
- }
-
- if(value == [NSNull null]) {
- continue;
- }
-
- Class propertyClass = nil;
- objc_property_t property = class_getProperty(modelClass, [propertyName UTF8String]);
- NSString *propertyAttributes = [NSString stringWithCString:property_getAttributes(property) encoding:NSUTF8StringEncoding];
- NSArray *splitPropertyAttributes = [propertyAttributes componentsSeparatedByString:@","];
- if(splitPropertyAttributes.count > 0) {
- NSString *encodeType = splitPropertyAttributes[0];
- if([encodeType hasPrefix:@"T@"]) {
- NSArray *splitEncodeType = [encodeType componentsSeparatedByString:@"\""];
- NSString *className = nil;
- if(splitEncodeType.count > 1) {
- className = splitEncodeType[1];
- }
- if(className) {
- propertyClass = NSClassFromString(className);
- }
- } else if ([encodeType isEqualToString:@"T{CLLocationCoordinate2D=dd}"]) {//经纬度
- //解析经纬度
- CLLocationCoordinate2D coordinate = [self coordinateFromModel:value];
- //使用msgSend直接设置经纬度的属性
- SEL sel = NSSelectorFromString([NSString stringWithFormat:@"set%@:",[propertyName capitalizedString]]);
- ((void (*)(id,SEL,CLLocationCoordinate2D))objc_msgSend)(ret,sel,coordinate);
- continue;
- } else if ([encodeType isEqualToString:@"T{CGPoint=dd}"]) {//CGPoint点
- CGPoint point = [AMapConvertUtil pointFromArray:value];
- //使用msgSend直接设置经纬度的属性
- SEL sel = NSSelectorFromString([NSString stringWithFormat:@"set%@:",[propertyName capitalizedString]]);
- ((void (*)(id,SEL,CGPoint))objc_msgSend)(ret,sel,point);
- continue;
- }
- }
- //获取property类型后,再处理
- if(propertyClass) {
- if([value isKindOfClass:propertyClass]) {
- //array 需要特殊处理
- if([propertyClass isSubclassOfClass:NSArray.class]) {
- NSString *elementClassSel = [NSString stringWithFormat:@"%@ElementClass", propertyName];
- SEL selector = NSSelectorFromString(elementClassSel);
- if([[ret class] respondsToSelector:selector]) {
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
- Class elementCls = [[ret class] performSelector:selector];
- #pragma clang diagnostic pop
- NSArray *arr = (NSArray *)value;
- NSMutableArray *mutArr = [NSMutableArray arrayWithCapacity:arr.count];
- for(id item in arr) {
- id newItem = [self modelFromDict:item modelClass:elementCls];
- if(newItem) {
- [mutArr addObject:newItem];
- } else {
- [mutArr addObject:item];
- }
- }
- [ret setValue:mutArr forKey:propertyName];
- } else {
- [ret setValue:value forKey:propertyName];
- }
- } else {
- [ret setValue:value forKey:propertyName];
- }
- } else if([value isKindOfClass:NSDictionary.class]){
- NSDictionary *tempDic = value;
- id model = [self modelFromDict:tempDic modelClass:propertyClass];
- [ret setValue:model forKey:propertyName];
- } else if ([value isKindOfClass:[NSNumber class]] && [NSStringFromClass(propertyClass) isEqualToString:@"UIColor"]) {
- UIColor *color = [AMapConvertUtil colorFromNumber:value];
- [ret setValue:color forKey:propertyName];
- } else {
- [ret setValue:value forKey:propertyName];
- #ifdef DEBUG
- Class valueClaz = [value class];
- NSLog(@"\U0001F913\U0001F913 Warning1: property '%@' of %@ is %@, %@ is received", propertyName, modelClass, propertyClass, valueClaz);
- #endif
- }
- } else { //end of if(propertyClaz) 如@"Ti" @"Tf"
- if([self isValidJsonValue:value]){
- [ret setValue:value forKey:propertyName];
- } else {
- #ifdef DEBUG
- Class valueClaz = [value class];
- NSLog(@"\U0001F913\U0001F913 Warning1: property '%@' of %@ is %@, %@ is received", propertyName, modelClass, propertyClass, valueClaz);
- #endif
- }
- }
- }
-
- #ifdef DEBUG
- if([missedProperties count] > 0) {
- NSLog(@"\U0001F913\U0001F913 Warning2: %@ value missed: %@", modelClass, missedProperties);
- }
- #endif
-
- NSString *postHookSel = [NSString stringWithFormat:@"postHookWith:"];
- SEL sel = NSSelectorFromString(postHookSel);
- if([ret respondsToSelector:sel]) {
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
- [ret performSelector:sel withObject:dict];
- #pragma clang diagnostic pop
- }
-
- return ret;
- }
- //返回array of propertyNames
- + (NSArray<NSString*> *)allPropertiesOfClass:(Class)cls {
- Class clazz = cls;
-
- NSMutableArray *mutArr = [[NSMutableArray alloc] init];
- while(clazz != [NSObject class]) {
- unsigned int count = 0;
- objc_property_t* properties = class_copyPropertyList(clazz, &count);
-
- for (int i = 0; i < count ; i++) {
- objc_property_t prop = properties[i];
- NSString *propertyName = [NSString stringWithCString:property_getName(prop) encoding:NSUTF8StringEncoding];
- [mutArr addObject:propertyName];
- }
-
- if(properties) {
- free(properties);
- }
-
- clazz = class_getSuperclass(clazz);
- }
-
- return mutArr;
- }
- //从数据model中解析经纬度
- + (CLLocationCoordinate2D)coordinateFromModel:(id)model {
- CLLocationCoordinate2D location = kCLLocationCoordinate2DInvalid;
- if ([model isKindOfClass:[NSArray class]]) {
- return [AMapConvertUtil coordinateFromArray:model];
- } else if ([model isKindOfClass:[NSString class]]) {//后台经纬度字符串习惯是(经度,维度)的格式
- NSString *coordStr = model;
- NSArray *array = [coordStr componentsSeparatedByString:@","];
- array = [[array reverseObjectEnumerator] allObjects];//这里需要逆置
- return [AMapConvertUtil coordinateFromArray:array];
- } else if ([model isKindOfClass:[NSDictionary class]]) {
- NSDictionary *dict = model;
- NSNumber *latitudeNum = [dict objectForKey:@"latitude"];
- NSNumber *longitudeNum = [dict objectForKey:@"longitude"];
- if (latitudeNum && longitudeNum) {
- location = CLLocationCoordinate2DMake([latitudeNum doubleValue], [longitudeNum doubleValue]);
- } else {
- NSLog(@"经纬度参数异常,解析为无效经纬度");
- }
- }
- return location;
- }
- @end
|