溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

從YYModel源碼中可以學(xué)到什么:前篇

發(fā)布時間:2020-07-24 11:44:56 來源:網(wǎng)絡(luò) 閱讀:3848 作者:Owenli_千 欄目:移動開發(fā)

前言

YYModel一個高性能模型框架。

作者在Github上給出的性能對比圖(iphone 6 y:時間)

從YYModel源碼中可以學(xué)到什么:前篇

YYModel:具體以下特點(diǎn):高性能、自動類型轉(zhuǎn)換、類型安全、非侵入性、輕量等。

關(guān)于如何使用YYModel查看文檔和示例【傳送門】。

本文主要任務(wù),分析YYModel的整體架構(gòu),實現(xiàn)思路,涉及到的知識點(diǎn)。

版本:1.0.4

文件結(jié)構(gòu)

從YYModel源碼中可以學(xué)到什么:前篇

YYModel,只有5個文件。接下我們會具體看這五個文件都做了什么工作。

  • YYModel.h頭文件,通過#import該文件使用庫。
  • YYClassInfo.h 根據(jù)名字應(yīng)該能猜出,關(guān)于Class信息的文件。
  • NSObject + YYModel.h 這個NSObject的一個Category。還定義了一些內(nèi)部類。

從YYModel源碼中可以學(xué)到什么:前篇

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

拓展:

  1. FOUNDATION_EXPORT是用來定義常量的,另外一個經(jīng)常用到的#define定義常量。

    那么兩者的區(qū)別?
    假設(shè)分別使用兩者定義字符串常量,前者可以通過==來判斷字符串是否相等,后者則需要使用isEqualToString:來判斷。因為,前者比較的是字符串指針地址,后者比較每個字符,因此前者效率更高。

  2. __has_include()

    #if __has_include(&lt;UIKit/UIKit.h&gt;)
    // 包含
    #else
    // 不包含
    #endif          
    

    判斷UIKit庫是否存在。

YYClassInfo

YYClassInfo文件中定義四個類,涉及到Runtime知識,請看這篇文章博文或者直接查看[objc4源碼]()

從YYModel源碼中可以學(xué)到什么:前篇

  • YYClassIvarInfo

    該類對應(yīng)實例變量信息(ivars),包含:名稱,偏移量,類型編碼,類型;其中類型請查看【官方文檔Type Encodings】

  • YYClassMethodInfo

    方法的信息類,包含,方法名稱,SEL,IMP,參數(shù)類型編碼,返回值類型編碼等。

  • YYClassPropertyInfo

    屬性信息類,包含名稱,類型,類型編碼,ivar名稱,類,協(xié)議列表,setter/getter等。

  • YYClassInfo:類信息。

拓展

Ivar, Method, Property, SEL, IMP都是什么?

理解這些需要對runtime了解,上面給出了博文鏈接,這里簡單復(fù)習(xí)一下。

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 //協(xié)議表 

};
/* Use `Class` instead of `struct objc_class *` */

Ivar指實例變量,存放在實例變量表中。Method方法,存放在方法表中。

接下再看一下Objc_method結(jié)構(gòu)體

struct objc_method {
    SEL method_name
    char * method_types
    IMP method_imp 
    }  

SEL指方法名稱,IMP指方法實現(xiàn)。

NSObject + YYModel

該文件定義三個分類和一個協(xié)議,以及兩個內(nèi)部類,下面是.h文件中提供的接口。

NSObject分類

提供了一些datamodel轉(zhuǎn)換的方法。

// 根據(jù)接收到JSON創(chuàng)建一個實例,該方法是線程安全的。
// json對象可以是 NSDictionary,NSString,NSData.
+ (nullable instancetype)yy_modelWithJSON:(id)json;

// 字典轉(zhuǎn)Model 
+ (nullable instancetype)yy_modelWithDictionary:(NSDictionary *)dictionary;

// 通過json設(shè)置屬性, 無效的數(shù)據(jù)會被忽略
- (BOOL)yy_modelSetWithJSON:(id)json;
- (BOOL)yy_modelSetWithDictionary:(NSDictionary *)dic;

// model轉(zhuǎn)json對象(NSDictionary/NSArray), NSData, NSString
- (nullable id)yy_modelToJSONObject;
- (nullable NSData *)yy_modelToJSONData;
- (nullable NSString *)yy_modelToJSONString;

#pragma mark - 其他快捷方法
// 拷貝(NSCoping協(xié)議)
- (nullable id)yy_modelCopy;

// 編碼和解碼(對應(yīng)NSCoding協(xié)議的兩個方法)
- (void)yy_modelEncodeWithCoder:(NSCoder *)aCoder;
- (id)yy_modelInitWithCoder:(NSCoder *)aDecoder;

// NSObject協(xié)議
// 哈希值
- (NSUInteger)yy_modelHash;
// 相等判斷
- (BOOL)yy_modelIsEqual:(id)model;
// Debug描述
- (NSString *)yy_modelDescription;

以上NSObject分類中提供的接口,具體實現(xiàn)稍后學(xué)習(xí)。

// 直接添加以下代碼即可自動完成
- (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]; }

NSArray分類

從json-array中創(chuàng)建一個數(shù)組, 其實也是遍歷循環(huán)調(diào)用字典轉(zhuǎn)Model。

+ (nullable NSArray *)yy_modelArrayWithClass:(Class)cls json:(id)json;

NSDictionary分類

從json創(chuàng)建字典。

+ (nullable NSDictionary *)yy_modelDictionaryWithClass:(Class)cls json:(id)json;

YYModel協(xié)議

YYModel協(xié)議,通過實現(xiàn)響應(yīng)的方法,可以提供白名單,黑名單,自定義屬性名稱等功能。

// 自定義屬性名稱,可以將json中的名稱映射到自定義的名稱,可以解決沖突例如`id`。
+ (nullable NSDictionary<NSString *, id> *)modelCustomPropertyMapper;

// 如果屬性是一個容器對象,例如NSArray/NSSet/NSDictonary,實現(xiàn)該方法可以返回一個映射字典(property -> class)
+ (nullable NSDictionary<NSString *, id> *)modelContainerPropertyGenericClass;

+ (nullable Class)modelCustomClassForDictionary:(NSDictionary *)dictionary;

// 白名單和黑名單(若實現(xiàn),忽略黑名單,只處理白名單)
+ (nullable NSArray<NSString *> *)modelPropertyBlacklist;
+ (nullable NSArray<NSString *> *)modelPropertyWhitelist;

- (NSDictionary *)modelCustomWillTransformFromDictionary:(NSDictionary *)dic;

// 數(shù)據(jù)驗證和自定義轉(zhuǎn)換
// 當(dāng)JSON轉(zhuǎn)為Model完成后,會調(diào)用該方法??梢栽谠摲椒ㄖ羞M(jìn)行校驗工作,返回NO該Model被忽略,也可以完成一些轉(zhuǎn)換工作。
- (BOOL)modelCustomTransformFromDictionary:(NSDictionary *)dic;
- (BOOL)modelCustomTransformToDictionary:(NSMutableDictionary *)dic;

拓展

  1. 在源碼中會發(fā)現(xiàn)有一對NS_ASSUME_NONNULL_BEGINNS_ASSUME_NONNULL_END宏。

    在Swift中存在Option類型,可以使用!?聲明變量,但是在OC中沒有這個特性。出現(xiàn)新的關(guān)鍵詞用于OC轉(zhuǎn)Swift時區(qū)分能否為空。

    nullable && nonnull

    nullable指對象可以為NULL。

    nonnull指對象不可以為NULL。

    如果不遵循這一規(guī)則,編譯器就會給出警告。

    為了簡化書寫,在NS_ASSUME_NONNULL_BEGINNS_ASSUME_NONNULL_END宏之間的代碼,默認(rèn)都是nonnull。所以我們只需指定哪些nullable的指針就可以了。
    StackOverflow關(guān)于該宏的問題。

其他知識點(diǎn)

接下來補(bǔ)充一些知識點(diǎn),或許對以后開發(fā)有幫助。

NS_OPTIONS && NS_ENUM

這是兩個簡單方便的宏定義,從iOS6開始,他們?nèi)〈嗽瓉淼?code>enum。

例如:

typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
    UITableViewCellStyleDefault,
    UITableViewCellStyleValue1,
    UITableViewCellStyleValue2,
    UITableViewCellStyleSubtitle
};

其中第一個元素存儲類型。第二個參數(shù)是名字。

另外,enum也可以被定義為按位掩碼。用簡單的OR和AND數(shù)學(xué)運(yùn)算既可實現(xiàn)一個整型值的編碼。請看這篇文章《NS_ OPTIONS && NS _ENUM - NShipster》。

小結(jié)

本章主要整理YYModel整體框架以及開發(fā)者提供的接口,并沒有涉及到內(nèi)部實現(xiàn)。接下來的文章,我將會一步步分析源碼實現(xiàn)。

參考

Github - ibireme/YYModel

個人博客Owenli
微博Owenli_千

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI