您好,登錄后才能下訂單哦!
YYModel
一個高性能模型框架。
作者在Github
上給出的性能對比圖(iphone 6 y:時間)
YYModel
:具體以下特點:高性能、自動類型轉換、類型安全、非侵入性、輕量等。
關于如何使用YYModel
查看文檔和示例【傳送門】。
本文主要任務,分析YYModel
的整體架構,實現思路,涉及到的知識點。
版本:1.0.4
YYModel
,只有5個文件。接下我們會具體看這五個文件都做了什么工作。
YYModel.h
頭文件,通過#import
該文件使用庫。YYClassInfo.h
根據名字應該能猜出,關于Class信息的文件。NSObject + YYModel.h
這個NSObject
的一個Category
。還定義了一些內部類。該文件只是一個頭文件,代碼很少。
#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
拓展:
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等。
拓展
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
}
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;
以上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;
從json創建字典。
+ (nullable NSDictionary *)yy_modelDictionaryWithClass:(Class)cls json:(id)json;
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_千
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。