从YYModel源码中可以学到什么:前篇
YYModel
一个高性能模型框架。
作者在Github
上给出的性能对比图(iphone 6 y:时间)
YYModel
:具体以下特点:高性能、自动类型转换、类型安全、非侵入性、轻量等。
关于如何使用YYModel
查看文档和示例【传送门】。
本文主要任务,分析YYModel
的整体架构,实现思路,涉及到的知识点。
版本:1.0.4
文件结构YYModel
,只有5个文件。接下我们会具体看这五个文件都做了什么工作。
YYModel.h
头文件,通过#import
该文件使用库。YYClassInfo.h
根据名字应该能猜出,关于Class信息的文件。NSObject + YYModel.h
这个NSObject
的一个Category
。还定义了一些内部类。YYModel头文件该文件只是一个头文件,代码很少。
#if __has_include(<YYModel/YYModel.h>)FOUNDATION_EXPORT double YYModelVersionNumber;FOUNDATION_EXPORT const unsigned char YYModelVersionString[];#import <YYModel/NSObject+YYModel.h>#import <YYModel/YYClassInfo.h>#else#import "NSObject+YYModel.h"#import "YYClassInfo.h"#endif
YYClassInfo拓展:
FOUNDATION_EXPORT
是用来定义常量的,另外一个经常用到的#define
定义常量。那么两者的区别?
假设分别使用两者定义字符串常量,前者可以通过==
来判断字符串是否相等,后者则需要使用isEqualToString:
来判断。因为,前者比较的是字符串指针地址,后者比较每个字符,因此前者效率更高。
__has_include()
#if __has_include(<UIKit/UIKit.h>)// 包含#else// 不包含#endif
判断
UIKit
库是否存在。
在YYClassInfo
文件中定义四个类,涉及到Runtime
知识,请看这篇文章博文或者直接查看[objc4源码]()
YYClassIvarInfo
该类对应实例变量信息(ivars),包含:名称,偏移量,类型编码,类型;其中类型请查看【官方文档Type Encodings】
YYClassMethodInfo
方法的信息类,包含,方法名称,SEL,IMP,参数类型编码,返回值类型编码等。
YYClassPropertyInfo
属性信息类,包含名称,类型,类型编码,ivar名称,类,协议列表,setter/getter等。
YYClassInfo:类信息。拓展
Ivar, Method, Property, SEL, IMP都是什么?
理解这些需要对
runtime
了解,上面给出了博文链接,这里简单复习一下。
typedef struct objc_method *Method; // 方法typedef struct objc_ivar *Ivar; // 实例变量typedef struct objc_category *Category; //分类typedef struct objc_property *objc_property_t; // 属性struct objc_class { Class isa Class super_class // 指向父类 const char * name // 名称 long version long info long instance_size struct objc_ivar_list * ivars // 实例变量表 struct objc_method_list * * methodLists //方法表 struct objc_cache * cache struct objc_protocol_list * protocols //协议表 };/* Use `Class` instead of `struct objc_class *` */
Ivar
指实例变量,存放在实例变量表中。Method
方法,存放在方法表中。
接下再看一下Objc_method
结构体
struct objc_method { SEL method_name char * method_types IMP method_imp }
NSObject + YYModel
SEL
指方法名称,IMP
指方法实现。
该文件定义三个分类和一个协议,以及两个内部类,下面是.h
文件中提供的接口。
提供了一些data
与model
转换的方法。
// 根据接收到JSON创建一个实例,该方法是线程安全的。// json对象可以是 NSDictionary,NSString,NSData.+ (nullable instancetype)yy_modelWithJSON:(id)json;// 字典转Model + (nullable instancetype)yy_modelWithDictionary:(NSDictionary *)dictionary;// 通过json设置属性, 无效的数据会被忽略- (BOOL)yy_modelSetWithJSON:(id)json;- (BOOL)yy_modelSetWithDictionary:(NSDictionary *)dic;// model转json对象(NSDictionary/NSArray), NSData, NSString- (nullable id)yy_modelToJSONObject;- (nullable NSData *)yy_modelToJSONData;- (nullable NSString *)yy_modelToJSONString;#pragma mark - 其他快捷方法// 拷贝(NSCoping协议)- (nullable id)yy_modelCopy;// 编码和解码(对应NSCoding协议的两个方法)- (void)yy_modelEncodeWithCoder:(NSCoder *)aCoder;- (id)yy_modelInitWithCoder:(NSCoder *)aDecoder;// NSObject协议// 哈希值- (NSUInteger)yy_modelHash;// 相等判断- (BOOL)yy_modelIsEqual:(id)model;// Debug描述- (NSString *)yy_modelDescription;
NSArray分类以上NSObject分类中提供的接口,具体实现稍后学习。
// 直接添加以下代码即可自动完成- (void)encodeWithCoder:(NSCoder *)aCoder { [self yy_modelEncodeWithCoder:aCoder]; }- (id)initWithCoder:(NSCoder *)aDecoder { self = [super init]; return [self yy_modelInitWithCoder:aDecoder]; }- (id)copyWithZone:(NSZone *)zone { return [self yy_modelCopy]; }- (NSUInteger)hash { return [self yy_modelHash]; }- (BOOL)isEqual:(id)object { return [self yy_modelIsEqual:object]; }- (NSString *)description { return [self yy_modelDescription]; }
从json-array中创建一个数组, 其实也是遍历循环调用字典转Model。
+ (nullable NSArray *)yy_modelArrayWithClass:(Class)cls json:(id)json;
NSDictionary分类
从json创建字典。
+ (nullable NSDictionary *)yy_modelDictionaryWithClass:(Class)cls json:(id)json;
YYModel协议
YYModel
协议,通过实现响应的方法,可以提供白名单,黑名单,自定义属性名称等功能。
// 自定义属性名称,可以将json中的名称映射到自定义的名称,可以解决冲突例如`id`。+ (nullable NSDictionary<NSString *, id> *)modelCustomPropertyMapper;// 如果属性是一个容器对象,例如NSArray/NSSet/NSDictonary,实现该方法可以返回一个映射字典(property -> class)+ (nullable NSDictionary<NSString *, id> *)modelContainerPropertyGenericClass;+ (nullable Class)modelCustomClassForDictionary:(NSDictionary *)dictionary;// 白名单和黑名单(若实现,忽略黑名单,只处理白名单)+ (nullable NSArray<NSString *> *)modelPropertyBlacklist;+ (nullable NSArray<NSString *> *)modelPropertyWhitelist;- (NSDictionary *)modelCustomWillTransformFromDictionary:(NSDictionary *)dic;// 数据验证和自定义转换// 当JSON转为Model完成后,会调用该方法。可以在该方法中进行校验工作,返回NO该Model被忽略,也可以完成一些转换工作。- (BOOL)modelCustomTransformFromDictionary:(NSDictionary *)dic;- (BOOL)modelCustomTransformToDictionary:(NSMutableDictionary *)dic;
其他知识点拓展
在源码中会发现有一对
NS_ASSUME_NONNULL_BEGIN
和NS_ASSUME_NONNULL_END
宏。在Swift中存在
Option
类型,可以使用!
和?
声明变量,但是在OC中没有这个特性。出现新的关键词用于OC转Swift时区分能否为空。
nullable
&&nonnull
nullable
指对象可以为NULL。
nonnull
指对象不可以为NULL。如果不遵循这一规则,编译器就会给出警告。
为了简化书写,在
NS_ASSUME_NONNULL_BEGIN
和NS_ASSUME_NONNULL_END
宏之间的代码,默认都是nonnull
。所以我们只需指定哪些nullable
的指针就可以了。
StackOverflow关于该宏的问题。
接下来补充一些知识点,或许对以后开发有帮助。
NS_OPTIONS
&& NS_ENUM
这是两个简单方便的宏定义,从iOS6开始,他们取代了原来的enum
。
例如:
typedef NS_ENUM(NSInteger, UITableViewCellStyle) { UITableViewCellStyleDefault, UITableViewCellStyleValue1, UITableViewCellStyleValue2, UITableViewCellStyleSubtitle};
其中第一个元素存储类型。第二个参数是名字。
另外,enum
也可以被定义为按位掩码。用简单的OR和AND数学运算既可实现一个整型值的编码。请看这篇文章《NS_ OPTIONS && NS _ENUM - NShipster》。
本章主要整理YYModel
整体框架以及开发者提供的接口,并没有涉及到内部实现。接下来的文章,我将会一步步分析源码实现。
Github - ibireme/YYModel
个人博客Owenli
微博Owenli_千
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。