亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

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

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

從YYModel源碼中可以學到什么:前篇

發布時間:2020-07-24 11:44:56 來源:網絡 閱讀:3898 作者:Owenli_千 欄目:移動開發

前言

YYModel一個高性能模型框架。

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

從YYModel源碼中可以學到什么:前篇

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

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

本文主要任務,分析YYModel的整體架構,實現思路,涉及到的知識點。

版本:1.0.4

文件結構

從YYModel源碼中可以學到什么:前篇

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

  • YYModel.h頭文件,通過#import該文件使用庫。
  • YYClassInfo.h 根據名字應該能猜出,關于Class信息的文件。
  • NSObject + YYModel.h 這個NSObject的一個Category。還定義了一些內部類。

從YYModel源碼中可以學到什么:前篇

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是用來定義常量的,另外一個經常用到的#define定義常量。

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

  2. __has_include()

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

    判斷UIKit庫是否存在。

YYClassInfo

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

從YYModel源碼中可以學到什么:前篇

  • 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 
    }  

SEL指方法名稱,IMP指方法實現。

NSObject + YYModel

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

NSObject分類

提供了一些datamodel轉換的方法。

// 根據接收到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]; }

NSArray分類

從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;

拓展

  1. 在源碼中會發現有一對NS_ASSUME_NONNULL_BEGINNS_ASSUME_NONNULL_END宏。

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

    nullable && nonnull

    nullable指對象可以為NULL。

    nonnull指對象不可以為NULL。

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

    為了簡化書寫,在NS_ASSUME_NONNULL_BEGINNS_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_千

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

汝州市| 扎兰屯市| 辰溪县| 剑河县| 天祝| 吉安县| 成安县| 古田县| 白银市| 潞西市| 新邵县| 清苑县| 拉萨市| 高密市| 苏尼特左旗| 黄龙县| 萝北县| 临高县| 曲沃县| 泌阳县| 河池市| 武安市| 大同市| 郁南县| 尚义县| 黄浦区| 日喀则市| 稷山县| 洛阳市| 德保县| 鲁甸县| 清水河县| 江达县| 神农架林区| 蒲城县| 淳化县| 嘉义县| 惠州市| 城步| 张家港市| 建昌县|