【Objective-C】利用Runtime实现对Json数据的ORM框架

202322575041259

一、代码:

//
// PBFORMTools.m
// PBFBaseToolsDemo
//
// Created by BY-MAC01 on 16/5/12.
// Copyright © 2016年 BY-MAC01. All rights reserved.
//

#import “PBFORMTools.h”
#import <objc/runtime.h>

@implementation PBFORMTools

//ORM框架,利用Runtime构建Model
+ (void)assembleDictionaryData:(NSObject*)objDes objRes:(NSDictionary*)objRes{
Class classType = [objDes class];
//NSArray类型对照表
NSDictionary *dicArrClassNames = nil;
NSString *strDicArrNames = @”_dicArrayClassName”;
Ivar ivarDicArrayClassNames = class_getInstanceVariable(classType, [strDicArrNames UTF8String]);
if(ivarDicArrayClassNames != NULL){
id idDicArray = object_getIvar(objDes, ivarDicArrayClassNames);
if ([idDicArray isKindOfClass:[NSDictionary class]]) {
dicArrClassNames = idDicArray;
}
}
if (objRes) {
for (NSString * keyNameRes in [objRes allKeys]) {
if (!keyNameRes || [keyNameRes length]<=0) {
continue;
}
//1、获取Class对应属性,判断属性类型
const char * attNameRes = [[NSString stringWithFormat:@”_%@”,keyNameRes] UTF8String];
Ivar varTmpDes = class_getInstanceVariable(classType,attNameRes);
//2、判断Json数据中,对应数据是否存在
//2.1、如不存在,continue
if (varTmpDes == NULL) {
continue;
}
//2.2、判断json数据和属性的类型是否一致
NSObject *objValueRes = [objRes objectForKey:keyNameRes];
const char *ivarType = ivar_getTypeEncoding(varTmpDes);
NSString *strIvarTypeDes = [NSString stringWithUTF8String:ivarType];
strIvarTypeDes = [strIvarTypeDes substringWithRange:NSMakeRange(2, [strIvarTypeDes length]-3)];
//2.2.1、NSString类型
if([objValueRes isKindOfClass:[NSString class]] && [strIvarTypeDes containsString:@”NSString”]){
//设置值
object_setIvar(objDes, varTmpDes, objValueRes);
}
//2.2.2、NSNumber类型
else if([objValueRes isKindOfClass:[NSNumber class]] && [strIvarTypeDes containsString:@”NSNumber”]){
//设置值
object_setIvar(objDes, varTmpDes, objValueRes);
}
//2.2.3、NSDictionary类型
//如属于NSDictionary、且Class该属性类型不属于上述类型,递归调用 assembleDictionaryData
else if ([objValueRes isKindOfClass:[NSDictionary class]]) {
//设置值
Class classDes = objc_getClass([strIvarTypeDes UTF8String]);
id objDesDic = [[classDes alloc] init];
[PBFORMTools assembleDictionaryData:objDesDic objRes:(NSDictionary*)objValueRes];
object_setIvar(objDes, varTmpDes, objDesDic);
}
//2.2.4、NSArray类型
//如类型属于NSArray、循环递归 assembleArrayData
else if ([objValueRes isKindOfClass:[NSArray class]]) {
//设置值
if (dicArrClassNames == NULL) {
continue;
}
id classType = [dicArrClassNames objectForKey:keyNameRes];
if (classType == NULL) {
continue;
}
NSObject *objNSArray = [PBFORMTools assembleArrayData:classType objRes:(NSArray*)objValueRes];
object_setIvar(objDes, varTmpDes, objNSArray);
}
}
}
return ;
}

//ORM框架,利用Runtime构建Model
+ (NSArray*)assembleArrayData:(Class)classType objRes:(NSArray*)objRes{
NSMutableArray *arrRtn = [[NSMutableArray alloc] init];
for(NSObject* objTmp in objRes){
//1、NSString类型
if([objTmp isKindOfClass:[NSString class]] && classType == [NSString class]){
//设置值
[arrRtn addObject:objTmp];
}
//2、NSNumber类型
else if([objTmp isKindOfClass:[NSNumber class]] && classType == [NSNumber class]){
//设置值
[arrRtn addObject:objTmp];
}
//3、属于NSArray,递归调用本方法 assembleArrayData
else if ([objTmp isKindOfClass:[NSArray class]]) {
NSArray *arrDes = [PBFORMTools assembleArrayData:classType objRes:(NSArray*)objTmp];
[arrRtn addObject:arrDes];
}
//4、不属于NSArray,属于NSDictionary,直接调用 assembleDictionaryData
else if ([objTmp isKindOfClass:[NSDictionary class]]) {
id objDes = [[classType alloc] init];
[PBFORMTools assembleDictionaryData:objDes objRes:(NSDictionary*)objTmp];
[arrRtn addObject:objDes];
}
}
return [arrRtn copy];
}

@end

 

 

二、单元测试:

//
// PBFORMToolsTests.m
// PBFBaseToolsDemo
//
// Created by BY-MAC01 on 16/5/12.
// Copyright © 2016年 BY-MAC01. All rights reserved.
//

#import <XCTest/XCTest.h>
#import “PBFORMTools.h”

//跟随者类
@interface PBFORMToolsTestModelFollower : NSObject
@property (nonatomic,strong)NSString *name;
@property (nonatomic,strong)NSNumber *code;
@end
@implementation PBFORMToolsTestModelFollower
@end

//主类
@interface PBFORMToolsTestModelUser : NSObject
@property (nonatomic,strong)NSMutableDictionary *KPBFORMToolsDicArrayName;
@property (nonatomic,strong)NSString *name;
@property (nonatomic,strong)NSNumber *code;
@property (nonatomic,strong)NSMutableArray *followers;
@property (nonatomic,strong)NSArray *date;
@property (nonatomic,strong)PBFORMToolsTestModelFollower *mainFollower;
@end
@implementation PBFORMToolsTestModelUser
– (instancetype)init{
self = [super init];
self.KPBFORMToolsDicArrayName = [[NSMutableDictionary alloc] init];
[self.KPBFORMToolsDicArrayName setValue:[PBFORMToolsTestModelFollower class] forKey:@”followers”];
[self.KPBFORMToolsDicArrayName setValue:[NSString class] forKey:@”date”];
return self;
}
@end

@interface PBFORMToolsTests : XCTestCase

@end

@implementation PBFORMToolsTests

– (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
}

– (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}

– (void)testAssembleByDictionary{
//构造
NSMutableDictionary *dicAttUser = [[NSMutableDictionary alloc] init];
[dicAttUser setValue:@”朱林” forKey:@”name”];
[dicAttUser setValue:[NSNumber numberWithInt:123456] forKey:@”code”];
//followers
NSMutableDictionary *dicAttFollower1 = [[NSMutableDictionary alloc] init];
[dicAttFollower1 setValue:@”张三” forKey:@”name”];
[dicAttFollower1 setValue:[NSNumber numberWithInt:456] forKey:@”code”];
NSMutableDictionary *dicAttFollower2 = [[NSMutableDictionary alloc] init];
[dicAttFollower2 setValue:@”李四” forKey:@”name”];
[dicAttFollower2 setValue:[NSNumber numberWithInt:789] forKey:@”code”];
NSArray *arrFollowers = [NSArray arrayWithObjects:dicAttFollower1,dicAttFollower2, nil];
[dicAttUser setValue:arrFollowers forKey:@”followers”];
//date
NSArray *arrDates = [NSArray arrayWithObjects:@”hello”,@”world”, nil];
[dicAttUser setValue:arrDates forKey:@”date”];
//mainFollower
NSMutableDictionary *dicAttFollowerMain = [[NSMutableDictionary alloc] init];
[dicAttFollowerMain setValue:@”王五” forKey:@”name”];
[dicAttFollowerMain setValue:[NSNumber numberWithDouble:789.23] forKey:@”code”];
[dicAttUser setValue:dicAttFollowerMain forKey:@”mainFollower”];

//work
PBFORMToolsTestModelUser *userInfo = [[PBFORMToolsTestModelUser alloc] init];
[PBFORMTools assembleDictionaryData:userInfo objRes:dicAttUser];

//断言
XCTAssertEqual(userInfo.name, @”朱林”,@”name error”);
XCTAssertEqual([userInfo.code integerValue], 123456,@”code error”);
XCTAssertEqual([userInfo.followers count],2 ,@”followers error”);
XCTAssertEqual([userInfo.date count],2 ,@”date error”);
XCTAssertEqual(userInfo.mainFollower.name, @”王五”,@”mainFollower.name error”);
XCTAssertEqual([userInfo.mainFollower.code doubleValue], 789.23,@”mainFollower.code error”);
}

– (void)testExample {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}

– (void)testPerformanceExample {
// This is an example of a performance test case.
[self measureBlock:^{
// Put the code you want to measure the time of here.
}];
}

@end