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


代码:

//
//  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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值