主要分析YYModel底层实现及使用
1、框架结构
主要包含5个文件
- YYClassInfo中,主要定义了4个类,分别用于表示实例变量、方法、属性、类信息
- NSObject+YYModel文件
- 3个分类:NSObject、NSArray、NSDictionary + 1个协议:YYModel协议
- 2个私有类:_YYModelPropertyMeta(属性元类信息)、_YYModelMeta(模型元类信息)
2、原理
- YYModel是无侵入方式解析数据,是通过category的方式提供相关解析方法
- 底层本质还是使用
objc_msgSend
发送setter、getter消息给属性元类
3、源码分析
4、使用场景
将常用的方法通过分类的方式进行封装,见文末。以下是不同场景调用的具体使用
- 1、简单的 JSON -- Model互转
- JSON --> Model:
yy_modelWithJSON
- Model --> JSON:
yy_modelToJSONString
//User模型类 @interface User : NSObject @property (nonatomic, assign) UInt64 uid; @property (nonatomic, copy) NSString *name; @property (nonatomic, strong) NSDate *created; @end
//1、简单的 model <---> JSON - (void)simpleUsed{ NSDictionary *json = @{ @"uid":@(123456), @"name":@"Harry", @"created":@"1965-07-31T00:00:00+0000" }; [self common:[User class] withJSON:json]; } //公共方法 - (void)common:(Class)cls withJSON:(id)json{ //JSON --> Model NSObject *object = [cls CJL_modelWithJSON:json]; NSLog(@"object = %@", [object description]); //Model --> JSON id json1 = [object CJL_modelToJSONObject]; NSLog(@"json1 = %@",json1); }
- 2、Model中key与属性名不同
- 通过
modelCustomPropertyMapper
将属性名与key做映射
//Book模型类 @interface Book : NSObject @property (nonatomic, copy) NSString *name; @property (nonatomic, assign) NSInteger page; @property (nonatomic, copy) NSString *desc; @property (nonatomic, copy) NSString *bookID; @end //----------------------------------- @implementation Book //返回一个 Dict,将 Model 属性名对映射到 JSON 的 Key。 + (NSDictionary *)modelCustomPropertyMapper{ return @{ @"name": @"n", @"page": @"p", @"desc": @"ext.desc", @"bookID": @[@"id", @"ID", @"book_id",] }; } @end
//2、Model属性名和JSON中的key不同 - (void)differentKeyUsed{ NSDictionary *json = @{ @"n": @"Harry Pottery", @"p": @(256), @"ext" : @{ @"desc" : @"A book written by J.K.Rowing." }, @"ID" : @(100010) }; [self common:[Book class] withJSON:json]; }
- 3、Model包含其他Model
//模型类: MiddleBook中 包含 Author @interface Author : NSObject @property (nonatomic, copy) NSString *name; @property (nonatomic, strong) NSDate *birthday; @end @interface MiddleBook : NSObject @property (nonatomic, copy) NSString *name; @property (nonatomic, assign) NSUInteger pages; @property (nonatomic, strong) Author *author; @end
//3、Model包含其他Model - (void)containModelUsed{ NSDictionary *json = @{ @"author":@{ @"name": @"J.K.Rowling", @"birthday": @"1965-07-31T00:00:00+0000" }, @"name": @"Harry Potter", @"pages": @(256) }; [self common:[MiddleBook class] withJSON:json]; }
- 4、Model包含容器类属性
@interface School : NSObject @property (nonatomic, copy) NSString *schoolName; @property (nonatomic, copy) NSArray *teachers; @end @interface Teacher : NSObject @property (nonatomic, copy) NSString *teacherName; @property (nonatomic, assign) NSInteger teacherAge; @end //----------------------------------- @implementation School // 返回容器类中的所需要存放的数据类型 (以 Class 或 Class Name 的形式)。 + (NSDictionary *)modelContainerPropertyGenericClass { return @{ @"teachers": [Teacher class], }; } @end @implementation Teacher @end
//4、容器类属性 - (void)containerUsed{ NSDictionary *json = @{ @"schoolName" : @"张三", @"teachers" : @[ @{@"teacherName": @"Sndday", @"teacherAge" : @(50)}, @{@"teacherName": @"Ssasas", @"teacherAge" : @(70)}, @{@"teacherName": @"Snddasa", @"teacherAge": @(30)} ], }; [self common:[School class] withJSON:json]; }
- 5、设置属性的黑名单与白名单
- 设置黑名单(忽略列表的属性):modelPropertyBlacklist
- 设置白名单(仅处理列表的属性):modelPropertyWhitelist
@interface Fans : NSObject @property (nonatomic, copy) NSString *avatorUrl; @property (nonatomic, copy) NSString *wxNickName; @property (nonatomic, copy) NSString *accountId; @property (nonatomic, copy) NSString *unionId; @property (nonatomic, copy) NSString *userid; @end //----------------------------------- @implementation Fans //如果实现了该方法,则处理过程中会忽略该列表内的所有属性 + (NSArray *)modelPropertyBlacklist{ return @[@"avatorUrl", @"accountId"]; } //如果实现了该方法,则处理过程中不会处理该列表外的属性。 + (NSArray *)å { return @[@"wxNickName"]; } @end
//5、黑名单与白名单 - (void)blackAndWhiteUsed{ NSDictionary *json = @{ @"accountId" : @"<null>", @"avatarUrl" : @"http://thirdwx.qlogo.cn/mmopen/vi_32/sqicFCgiaheqCFbjrYgTmwXUQOB5l5Iyo47cVVp2cLlHARck6XgXscqicJ2ZVibicCbGH4iaVcQz8ptXqbV6n9ic5iaL9g/132", @"unionId" : @"o2t87wKAR1pNRZR0cnReBT608mok", @"userid" : @(11703346), @"wxNickName" : @"Bob" }; [self common:[Fans class] withJSON:json]; }
- 6、数据校验与自定义转换:可以根据自己的需求,自行自动定义的解析
@interface Student : NSObject @property (nonatomic, copy) NSString *name; @property (nonatomic, strong) NSDate *createAt; @end //----------------------------------- @implementation Student // 当 JSON 转为 Model 完成后,该方法会被调用。 // 你可以在这里对数据进行校验,如果校验不通过,可以返回 NO,则该 Model 会被忽略。 // 你也可以在这里做一些自动转换不能完成的工作。 - (BOOL)modelCustomTransformFromDictionary:(NSDictionary *)dic{ NSNumber *timestamp = dic[@"timestamp"]; if (![timestamp isKindOfClass:[NSNumber class]]) return NO; _createAt = [NSDate dateWithTimeIntervalSince1970:timestamp.floatValue]; return YES; } // 当 Model 转为 JSON 完成后,该方法会被调用。 // 你可以在这里对数据进行校验,如果校验不通过,可以返回 NO,则该 Model 会被忽略。 // 你也可以在这里做一些自动转换不能完成的工作。 - (BOOL)modelCustomTransformToDictionary:(NSMutableDictionary *)dic { if (!_createAt) return NO; dic[@"timestamp"] = @(_createAt.timeIntervalSince1970); return YES; } @end
//6、数据校验与自定义转换 - (void)transformUsed{ NSDictionary *json = @{ @"name": @"Harry", @"timestamp" : @(1445534567) }; [self common:[Student class] withJSON:json]; }
具体的封装如下所示
- h文件
@interface NSObject (CJLModel) //JSON 转 model + (instancetype)CJL_modelWithJSON:(id)json; //字典 转 model + (instancetype)CJL_modelWithDictionary:(NSDictionary *)dic; //model 转 JSON - (NSString *)CJL_modelToJSONString; //model 转 对象 - (NSString *)CJL_modelToJSONObject; //model 转 data - (NSString *)CJL_modelToJSONData; @end @interface NSArray (CJLModel) //JSON转数组 + (NSArray *)CJL_modelArrayWithClass:(Class)cls json:(id)json; @end @interface NSDictionary (CJLModel) //JSON转字典 + (NSDictionary *)CJL_modelDictionaryWithClass:(Class)cls json:(id)json; @end @protocol CJLModel <YYModel> @end
- m文件
#import "NSObject+CJLModel.h" @implementation NSObject (CJLModel) //JSON 转 model + (instancetype)CJL_modelWithJSON:(id)json{ return [[self class] yy_modelWithJSON:json]; } //字典 转 model + (instancetype)CJL_modelWithDictionary:(NSDictionary *)dic{ return [[self class] yy_modelWithDictionary:dic]; } //model 转 JSON - (NSString *)CJL_modelToJSONString{ return [self yy_modelToJSONString]; } //model 转 对象 - (NSString *)CJL_modelToJSONObject{ return [self yy_modelToJSONObject]; } //model 转 data - (NSString *)CJL_modelToJSONData{ return [self yy_modelToJSONData]; } @end @implementation NSArray (CJLModel) //JSON转数组 + (NSArray *)CJL_modelArrayWithClass:(Class)cls json:(id)json{ return [[self class] yy_modelArrayWithClass:cls json:json]; } @end @implementation NSDictionary (CJLModel) //JSON转字典 + (NSDictionary *)CJL_modelDictionaryWithClass:(Class)cls json:(id)json{ return [[self class] CJL_modelDictionaryWithClass:cls json:json]; } @end