ふるすたっくえんじにあっぽい人の日記

ASP .NET MVC (C#)、.NET Framework、iOS (Objective-c) アプリ、Androidアプリ (Java)、AWS、たまにLAMPとかプロジェクトマネジメントあたりのお話

【iOS】JSONから自作クラスのシリアライズ

疲れたので多くは語りません。
この人を継承したクラスを作ってプロパティを宣言してあげてください。

APIResponseBase.h

@interface APIResponseBase : NSObject

- (id)initWithDictionary:(NSDictionary *)dic;

- (Class)getArrayItemType:(NSString *)propertyName;

@end

APIResponseBase.m

#import "APIResponseBase.h"
#import <objc/message.h>

@implementation APIResponseBase

- (id)initWithDictionary:(NSDictionary *)dic {
	self = [super init];
	if (self != NULL) {
		unsigned int cnt = 0;
		objc_property_t *properties = class_copyPropertyList([self class], &cnt);
		for (NSInteger i = 0; i < cnt; i++) {
			[self setValueFromProperty:properties[i] andDictionary:dic];
		}
		free(properties);
	}
	return self;
}

- (Class)getArrayItemType:(NSString *)propertyName {
	return nil;
}

- (void)setValueFromProperty:(objc_property_t)property andDictionary:(NSDictionary *)dic {
	if (![dic isEqual:[NSNull null]]) {
		NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)];
		NSMutableDictionary *setValueDic = [[NSMutableDictionary alloc]initWithCapacity:dic.allKeys.count];
		Class propertyType = [self propertyTypeOfProperty:property_getAttributes(property)];
		if ([dic.allKeys containsObject:propertyName]) {
			if (propertyType == nil || propertyType == [NSString class] || propertyType == [NSNumber class]) {
				[setValueDic setObject:[dic objectForKey:propertyName] forKey:propertyName];
			}
			else if (propertyType == [NSArray class] || propertyType == [NSMutableArray class]) {
				NSArray *array = [dic objectForKey:propertyName];
				NSMutableArray *propArray = [[NSMutableArray alloc]initWithCapacity:array.count];
				for (id d in array) {
					Class class = [self getArrayItemType:propertyName];
					if ([class isSubclassOfClass:[APIResponseBase class]]) {
						[propArray addObject:[((APIResponseBase *)[class alloc])initWithDictionary : d]];
					}
					else {
						if ([d class] == [NSDictionary class]) {
							for (NSString *key in ((NSDictionary *)d).allKeys) {
								[propArray addObject:[d objectForKey:key]];
							}
						}
						else {
							[propArray addObject:d];
						}
					}
				}
				[self setValue:propArray forKey:propertyName];
				array = NULL;
			}
			else {
				[self setValue:[((APIResponseBase *)[propertyType alloc])initWithDictionary :[dic objectForKey:propertyName]] forKey:propertyName];
			}
		}
		[self setValuesForKeysWithDictionary:setValueDic];
	}
}

- (Class)propertyTypeOfProperty:(const char *)attr {
	NSString * const attributes = [NSString stringWithCString:attr encoding:NSUTF8StringEncoding];
	NSRange const typeRangeStart = [attributes rangeOfString:@"T@\""];
	if (typeRangeStart.location != NSNotFound) {
		NSString * const typeStringWithQuote = [attributes substringFromIndex:typeRangeStart.location + typeRangeStart.length];
		NSRange const typeRangeEnd = [typeStringWithQuote rangeOfString:@"\""];
		if (typeRangeEnd.location != NSNotFound) {
			NSString * const typeString = [typeStringWithQuote substringToIndex:typeRangeEnd.location];
			return NSClassFromString(typeString);
		}
	}
	return nil;
}

@end