iOS源代碼分析 ---- MJExtension(一)

一直以為能夠讀懂源代碼是件很牛的事情,但是每次都被動輒復(fù)雜的語法的架構(gòu)嚇跑,在偶然看到一個叫Draveness的大牛寫的源代碼分析博客,耐著性子看完了一篇SDWebImage框架的分析,才發(fā)覺其實啃源代碼沒那么可怕,而且對于功力的提升十分顯著,尤其偶爾接觸到的底層的理解讓我豁然開朗,遂打算獨自寫一篇第三方框架的源代碼分析作為自己的第一篇技術(shù)博客.

MJExtension

A fast, convenient and nonintrusive conversion between JSON and model.

MJExtension是一套字典和模型之間互相轉(zhuǎn)換的超輕量級框架.

能做什么

  • 字典(JSON)--> 模型(Model) CoreData模型(Core Data Model)
  • JSON字符串(JSONString) --> 模型(Model)、CoreData模型(Core Data Model)
  • 模型(Model)、CoreData模型(Core Data Model) --> 字典(JSON)
  • JSON數(shù)組(JSON Array) --> 模型數(shù)組(Model Array)、CoreData模型數(shù)組(Core Data Model Array)
  • JSON字符串(JSONString) --> 模型數(shù)組(Model Array)、CoreData模型數(shù)組(Core Data Model Array)
  • 模型數(shù)組(Model Array)、CoreData模型數(shù)組(Core Data Model Array) --> 字典數(shù)組(JSON Array)
  • 只需要一行代碼,就能實現(xiàn)模型的所有屬性進行Coding(歸檔和解檔)

字典 -> 模型

MJExtension提供了一個類方法進行字典轉(zhuǎn)模型的工作,我們通過對
+ (instancetype)mj_objectWithKeyValues:(id)keyValues方法解析,來開始本篇分析.下面讓我們打開這個方法的實現(xiàn)代碼NSObject+MJKeyValue.m.

當(dāng)然你也可以git clone github git@github.com:CoderMJLee/MJExtension.git到本地來看.

+ (instancetype)mj_objectWithKeyValues:(id)keyValues
{
    return [self mj_objectWithKeyValues:keyValues context:nil];
}

使用這個類方法的唯一作用就是調(diào)用了另一個方法

+ (instancetype)mj_objectWithKeyValues:(id)keyValues context:(NSManagedObjectContext *)context
{
    // 獲得JSON對象
    keyValues = [keyValues mj_JSONObject];
    MJExtensionAssertError([keyValues isKindOfClass:[NSDictionary class]], nil, [self class], @"keyValues參數(shù)不是一個字典");
    
    if ([self isSubclassOfClass:[NSManagedObject class]] && context) {
        return [[NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass(self) inManagedObjectContext:context] mj_setKeyValues:keyValues context:context];
    }
    return [[[self alloc] init] mj_setKeyValues:keyValues];
}

下面我們就仔細分析一下這個方法的實現(xiàn)過程.

兩個參數(shù)

  • (id)keyValues 用來接收傳入的字典,將參數(shù)寫為id類型是為了能夠接收所有類型的參數(shù)
  • (NSManagedObjectContext *)context (NSManagedObjectContext)是一個對于數(shù)據(jù)庫的封裝,只要能保存在數(shù)據(jù)庫中的內(nèi)容,都可以保存在NSManagedObjectContext中.

獲取對象

方法的第一步是接收傳入的對象

- (id)mj_JSONObject
{
    if ([self isKindOfClass:[NSString class]]) {
        return [NSJSONSerialization JSONObjectWithData:[((NSString *)self) dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil];
    } else if ([self isKindOfClass:[NSData class]]) {
        return [NSJSONSerialization JSONObjectWithData:(NSData *)self options:kNilOptions error:nil];
    }
    
    return self.mj_keyValues;
}

如果傳入對象是NSString類型或者NSData類型,會使用系統(tǒng)自帶的數(shù)據(jù)類型轉(zhuǎn)換將對象轉(zhuǎn)換成JSON類型返回,否則返回自己.

構(gòu)建錯誤

第二行代碼使用了一個自定義的方法MJExtensionAssertError

#define MJExtensionAssertError(condition, returnValue, clazz, msg) \
[clazz setMj_error:nil]; \
if ((condition) == NO) { \
    MJExtensionBuildError(clazz, msg); \
    return returnValue;\
}

通過第一步的轉(zhuǎn)換,傳入的對象會是JSON類型或其他類型的一種,如果傳入的不是JSON類型,MJExtensionBuildError會調(diào)用runtime中的objc_setAssociatedObject方法為當(dāng)前類關(guān)聯(lián)一個NSError對象,用來生成錯誤日志.
在龐大的項目中難免會遇到傳值錯誤類型的低級錯誤,這個方法可以讓用戶在debug的過程中準(zhǔn)確找出錯誤位置并進行修改.
這里作者為clazz這個參數(shù)的定義是[self class],即自身類別.

context參數(shù)處理

接下來會進行context參數(shù)的處理

if ([self isSubclassOfClass:[NSManagedObject class]] && context) { return [[NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass(self) inManagedObjectContext:context] mj_setKeyValues:keyValues context:context]; }

如果調(diào)用此方法的類別為NSManagedObject的子類而且傳入的context不為空,則會實例一個NSEntityDescription對象重新進行類型轉(zhuǎn)換.

實例化對象

return [[[self alloc] init] mj_setKeyValues:keyValues];

最后實例化一個self類型的對象進行類型轉(zhuǎn)換操作.


以上行為我稱之為是對參數(shù)的預(yù)處理,只有傳入正確或者通過處理后能夠進行類型轉(zhuǎn)換的參數(shù)后才能夠正確的進行類型轉(zhuǎn)換方法.

類型轉(zhuǎn)換

+ (instancetype)mj_objectWithKeyValues:(id)keyValues context:(NSManagedObjectContext *)context最后一步進入類型轉(zhuǎn)換處理,在這里進行的是JSON轉(zhuǎn)Model行為.

- (instancetype)mj_setKeyValues:(id)keyValues context:
(NSManagedObjectContext *)context```
由于這個方法的實現(xiàn)代碼太長,在這里就不再貼出全部代碼,后文會挑選關(guān)鍵代碼進行分析.


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容