利用Runtime实现对Json数据的ORM框架

来源:互联网 发布:剑龙网络 编辑:程序博客网 时间:2024/06/06 02:55


代码:

////  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




0 0