iOS Model模型转换三方调研
2018-04-19 本文已影响96人
spades_K
传统的KVC实现模型转换
定义一个User类
@interface User : NSObject
@property(copy,nonatomic) NSString *name;
@property(copy,nonatomic) NSString *gender;
@property(copy,nonatomic) NSString *age;
@property(copy,nonatomic) NSString *userId;
@property(copy,nonatomic) NSMutableArray *roles;
@end
耗时计算
//
// ViewController.m
// ModelConversionContrast
//
// Created by rck on 2018/4/19.
// Copyright © 2018年 RCK. All rights reserved.
//
#import "ViewController.h"
#import "Models.h"
#import <MJExtension.h>
#import <YYModel.h>
@interface ViewController ()
@property(strong,nonatomic)NSDictionary *userDict;
@end
// 测试次数
static int testCout = 10;
// 转换次数
static int contrastCout = 10000;
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// KVC耗时(性能最佳 后面就不比对多model嵌套问题了)。
[self kvcModelContrast];
// MJExtension 耗时
[self mjextensionContrast];
// YYModel耗时
[self yyModelContrast];
// Do any additional setup after loading the view, typically from a nib.
}
#pragma mark - KVC
- (void)kvcModelContrast
{
// 定义模型字典
double allTime = 0;
for (int i = 0; i <testCout; i++) {
// 毫秒
double stDate = [[NSDate date] timeIntervalSince1970] *1000;
for (int i = 0; i <contrastCout; i++) {
User *user = [[User alloc] init];
[user setValuesForKeysWithDictionary:self.userDict];
}
// 毫秒
double edDate = [[NSDate date] timeIntervalSince1970] *1000;
// NSLog(@"耗时-----%f毫秒",edDate-stDate);
allTime += (edDate-stDate);
}
NSLog(@"KVC 单层模型转换 方法执行%d次 循环转换%d次,平均耗时%f毫秒",testCout,contrastCout,allTime/testCout);
}
#pragma mark - 三方获取属性方法
- (void)getAllPropertys
{
unsigned int propertyCount = 0;
///通过运行时获取当前类的属性
objc_property_t *propertys = class_copyPropertyList([User class], &propertyCount);
//把属性放到数组中
for (int i = 0; i < propertyCount; i ++) {
///取出第一个属性
objc_property_t property = propertys[i];
//得到属性对应的名称
NSString *name = @(property_getName(property));
NSLog(@"name:%@", name);
}
}
#pragma mark - MJEXtension
- (void)mjextensionContrast
{
// 定义模型字典
double allTime = 0;
for (int i = 0; i <testCout; i++) {
// 毫秒
double stDate = [[NSDate date] timeIntervalSince1970] *1000;
for (int i = 0; i <contrastCout; i++) {
User *user = [[User alloc] init];
[user mj_setKeyValues:self.userDict];
// NSLog(@"替换的 id 属性%@ 容器model容器 %@",user.userId,user.roles); // 替换的 id 属性1
}
// 毫秒
double edDate = [[NSDate date] timeIntervalSince1970] *1000;
// NSLog(@"耗时-----%f毫秒",edDate-stDate);
allTime += (edDate-stDate);
}
NSLog(@"MJEXtension %@层模型转换 执行%d次 循环转换%d次,平均耗时%f毫秒",self.userDict[@"roles"]?@"多":@"单", testCout,contrastCout,allTime/testCout);
}
#pragma mark YYModel
- (void)yyModelContrast
{
// 定义模型字典
double allTime = 0;
for (int i = 0; i <testCout; i++) {
// 毫秒
double stDate = [[NSDate date] timeIntervalSince1970] *1000;
for (int i = 0; i <contrastCout; i++) {
User *user = [User yy_modelWithJSON:self.userDict];
// NSLog(@"替换的 id 属性%@ 容器model容器 %@",user.userId,user.roles); // 替换的 id 属性1
}
// 毫秒
double edDate = [[NSDate date] timeIntervalSince1970] *1000;
// NSLog(@"耗时-----%f毫秒",edDate-stDate);
allTime += (edDate-stDate);
}
NSLog(@"YYModel %@层模型转换 执行%d次 循环转换%d次,平均耗时%f毫秒",self.userDict[@"roles"]?@"多":@"单", testCout,contrastCout,allTime/testCout);
}
#pragma mark - SetterAndGetters
- (NSDictionary *)userDict
{
return @{@"name":@"Jack",
@"gender":@"man",
@"age":@"18",
@"id":@"1"
/* 注释下面则为单层model*/
,@"roles":@[@{@"name":@"staff"},
@{@"name":@"citizen"}]
};
}
@end
优点:
- 单层Model一句话转换,简洁方便。
缺点:
- 实际使用中需定义 setValue:forUndefinedKey:方法不然容易崩溃。
- 遇到model嵌套情况代码量增大,需要循环创建处理。
- 对数据的容错率低,需要判断后台返回数据是否符合,出现null数据可能导致程序崩溃。
三方框架的优点
- 它的兼容性好,拓展性强,使代码更健壮。
- 很大程度的缩减代码量。
- 转化效率?
时效对比 KVC与MJExtension单层model转换
2018-04-19 15:26:49.905309+0800[2065:491747] KVC 单层模型转换 方法执行10次 循环转换10000次,平均耗时24.895508毫秒
2018-04-19 15:26:52.922414+0800[2065:491747] MJEXtension 单层模型转换 执行10次 循环转换10000次,平均耗时301.692432毫秒
介绍几个主流的iOS转换Model框架
1.MJExtension
MJExtension.png 161d2039c2a5a948.png代码详解见这里✋
使用方法 全中文注释
引入工程:21个文件80K 量级较大 功能也支持很多比如支持CoreData plist 与Model的转话等。类目较多,如果只是简单的转换 不推荐引入。
常用方法
/**
@implementation User
key值替换
@return @{需要的值:替换的值}
*/
+ (NSDictionary *)mj_replacedKeyFromPropertyName
{
return @{@"userId":@"id"// key对应数组,数组里面为模型
};
}
/**
model嵌套问题
@return @{接受的key值:[需要嵌套在内的类 class]};
*/
+ (NSDictionary *)mj_objectClassInArray
{
return @{@"roles":[Role class]};
}
@end
YYModel
YYModel.png代码详解见这里✋1 代码详解见这里✋2
使用方法见这里✋
引入工程:5个文件 120k。
先看下转化效率对比
- 多层模型
2018-04-19 16:11:35.197779+0800 ModelConversionContrast[2085:498926] MJEXtension 多层模型转换 执行10次 循环转换10000次,平均耗时822.410645毫秒
2018-04-19 16:11:36.473886+0800 ModelConversionContrast[2085:498926] YYModel 多层模型转换 执行10次 循环转换10000次,平均耗时127.587207毫秒
- 单层模型
2018-04-19 16:13:25.193517+0800 ModelConversionContrast[2088:499480] KVC 单层模型转换 方法执行10次 循环转换10000次,平均耗时24.614404毫秒
2018-04-19 16:13:28.180702+0800 ModelConversionContrast[2088:499480] MJEXtension 单层模型转换 执行10次 循环转换10000次,平均耗时298.698267毫秒
2018-04-19 16:13:28.680770+0800 ModelConversionContrast[2088:499480] YYModel 单层模型转换 执行10次 循环转换10000次,平均耗时49.986694毫秒
常用方法
@implementation User
#pragma mark -YYModel
/**
key值替换问题
@return @{接受的key值:[需要嵌套在内的类 class]};
*/
+ (NSDictionary *)modelCustomPropertyMapper {
return @{@"userId":@"id"};
// 例子 bookID 支持 多个替换值
// + (NSDictionary *)modelCustomPropertyMapper {
// return @{@"name" : @"n",
// @"page" : @"p",
// @"desc" : @"ext.desc",
// @"bookID": @[@"id", @"ID", @"book_id"]};
// }
}
/**
model替换
@return 返回容器类中的所需要存放的数据类型 (以 Class 或 Class Name 的形式)。
*/
+ (NSDictionary *)modelContainerPropertyGenericClass {
return @{@"roles":[Role class]};
// return @{@"roles":@"Role"};
}
@end