YYModel源碼閱讀筆記(一)

model和json轉(zhuǎn)換時開發(fā)中普遍使用的魔招,在iOS開發(fā)中系統(tǒng)KVO本身也提供了簡單的API:

同時常用流行的model和json的轉(zhuǎn)化框架有MJExtension、Mantle五辽、JSONModel办斑、YYModel等。今天主要就YYModel得源碼做一個剖析杆逗,延續(xù)之前風(fēng)格乡翅,還是通過一個典型的應(yīng)用展開分析。

首先讓我們看一下這個框架的基本結(jié)構(gòu):

可以看到這是一個很輕量簡潔的工具罪郊,只有四個文件蠕蚜,其中NSObject+YYModel是NSObject的categary提供了相應(yīng)的使用接口,和Mantle相比沒有侵入性悔橄,YYClassInfo類是針對NSObject的Ivar靶累、Property、Method進(jìn)行封裝的類癣疟,之后具體分析挣柬。

下邊先看一個調(diào)用:

以上是YYKit的demo中一個簡單實(shí)例。

之下就從json轉(zhuǎn)model的API開始分析:

NSDictionary *dic = [self _yy_dictionaryWithJSON:json]可以看出睛挚,由于傳入的jsonid類型邪蛔,所以首先要將其轉(zhuǎn)化為NSDictionary*類型,然后就變了字典轉(zhuǎn)模型扎狱。先具體分析一下這個將json轉(zhuǎn)化為字典的方法:

可看出如果json為空侧到,直接返回的dic也是空勃教,如果json是字典直接返回,如果是字符串則調(diào)用系統(tǒng)方法jsonData = [(NSString *)json dataUsingEncoding : NSUTF8StringEncoding]將其轉(zhuǎn)化為NSData*類型的jsonData匠抗,如果jsonNSData*類型則直接將json返給jsonData荣回,然后調(diào)用系統(tǒng)方法dic = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:NULL]jsonData轉(zhuǎn)化為字典dic并返回。

接下來看這個將字典轉(zhuǎn)化為model的方法:[self modelWithDictionary:dic]

如果傳入?yún)?shù)dictionary為空或不是字典戈咳,返nil心软。

Class cls = [self class]返回類本身。

_YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:cls]創(chuàng)建了一個_YYModelMeta*類型的對象modelMeta著蛙。

接下來就從這個初始化工廠方法入手删铃,詳細(xì)分析_YYModelMeta這個類:

方法前半部分說明,cache是在程序運(yùn)行期間只生成一次的靜態(tài)變量踏堡,lock在這里是用信號量實(shí)現(xiàn)的安全鎖猎唁,從_YYModelMeta *meta = CFDictionaryGetValue(cache, (__bridge const void *)(cls))可以看出cache是在程序運(yùn)行期間緩存每個cls對應(yīng)的_YYModelMeta *類型的meta對象。

所以這個方法就是如果全局還沒有cache顷蟆,則創(chuàng)建cache诫隅,并創(chuàng)建安全鎖lock,然后從cache中獲取以clskey值對應(yīng)的_YYModelMeta*類型的對象帐偎,如果沒有或?qū)ο笮枰聞t調(diào)用meta = [[_YYModelMeta alloc] initWithClass:cls]創(chuàng)建meta對象逐纬,并插入到cache中,整個過程通過lock鎖保證了線程安全削樊。

在深入探討具體的初始化成員方法:

可以看出這是一個很龐大的方法豁生。YYClassInfo *classInfo = [YYClassInfo classInfoWithClass:cls]這一步是闖將一個YYClassInfo*類型的對象classInfo,開篇提到過YYClassInfo是用來存儲一些類信息的漫贞,現(xiàn)在就具體深入到這個方法中:

類似于_YYModelMeta的工廠方法甸箱,先在緩存中查YYClassInfo *info,如果沒有迅脐,則調(diào)用info = [[YYClassInfo alloc] initWithClass:cls]方法創(chuàng)建芍殖,創(chuàng)建完后將其存入相應(yīng)的緩存中(classCachemetaCache)。

再深入探查YYClassInfo的具體初始化方法:

在這個方法中依次保存了@property (nonatomic, assign, readonly) Class cls谴蔑,@property (nullable, nonatomic, assign, readonly) Class superCls豌骏,@property (nullable, nonatomic, assign, readonly) Class metaCls@property (nonatomic, strong, readonly) NSString *name這些屬性树碱。

再看[self _update]這個方法做了什么:

可以看出這個方法主要是為@property (nullable, nonatomic, strong, readonly) NSDictionary<NSString *, YYClassIvarInfo *> *ivarInfos肯适,@property (nullable, nonatomic, strong, readonly) NSDictionary<NSString *, YYClassMethodInfo *> *methodInfos@property (nullable, nonatomic, strong, readonly) NSDictionary<NSString *, YYClassPropertyInfo *> *propertyInfos這三個屬性賦值成榜。

其中_ivarInfos存儲了類的所有成員變量框舔,_methodInfos類的所有成員方法,_propertyInfos存儲了類的所有屬性。

_methodInfos為類:

先是通過runtime方法Method*methods =class_copyMethodList(cls, &methodCount)獲取類的所有方法刘绣,然后遍歷方法樱溉,針對每個方法創(chuàng)建一個YYClassMethodInfo *類型的info:

可以看出YYClassMethodInfo保存了方法名、方法選擇子纬凤、函數(shù)指針福贞、參數(shù)類型等,然后調(diào)用方法if(info.name) methodInfos[info.name] = info以方法名字為key值停士,以YYClassMethodInfo *infovalue值挖帘,將所有方法存進(jìn)_methodInfos字典中。_ivarInfos_propertyInfos類似恋技,也都是用字典存儲了所有的屬性和成員變量拇舀。最后設(shè)置_needUpdate = NO。

再回到YYClassInfo- (instancetype)initWithClass:(Class)cls方法中:_superClassInfo = [self.class classInfoWithClass:_superCls]再依次創(chuàng)建模型父類的YYClassInfo*類型的對象并保存在緩存中蜻底。

接著回到_YYModelMeta的- (instancetype)initWithClass:(Class)cls方法中骄崩。

統(tǒng)計(jì)黑名單和白名單。

這一步是獲取容器屬性中的類型信息薄辅。

這一步遍歷之前生成的propertyInfos要拂,先根據(jù)黑名單和白名單做相應(yīng)的過濾,針對需要在模型轉(zhuǎn)化中應(yīng)用的屬性進(jìn)行一個_YYModelPropertyMeta*類型的封裝站楚,然后保存在allPropertyMetas中脱惰,并將allPropertyMetas字典中的所有value值賦給_allPropertyMetas屬性。

如果模型自定義的屬性和字典的key值不一致的話源请,這一步是建立一個影射(需要在模型中實(shí)現(xiàn)modelCustomPropertyMapper方法枪芒,在這個方法中返回映射字典)。然后將相關(guān)影射信息存在_mapper屬性中谁尸。


最后對_YYModelMeta*類型的meta進(jìn)行賦值,然后返回纽甘。

就此良蛮,_YYModelMeta類的- (instancetype)initWithClass:(Class)cls方法結(jié)束。

返回到+ (instancetype)metaWithClass:(Class)cls方法中:

_YYModelMeta*meta放入緩存中悍赢,這個方法也結(jié)束决瞳。

經(jīng)過如此繁雜的操作,你是否已經(jīng)迷路了呢左权,現(xiàn)在回到字典轉(zhuǎn)模型這一步了:

上面的操作就是_YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:cls]這一步皮胡,這一步就是將模型類的相關(guān)屬性、成員變量赏迟、方法屡贺、黑名單、白名單、模型屬性和字典索引之間影射等信息取出來并全局緩存甩栈,在下次調(diào)用的時候直接獲取可以大大提高運(yùn)行速度泻仙。

下面就開始分析將字典轉(zhuǎn)化為模型的方法:

先創(chuàng)建一個模型對象,再通過調(diào)用方法[one modelSetWithDictionary:dictionary]給對象賦值:

在這個方法中調(diào)用CFArrayApplyFunction((CFArrayRef)modelMeta->_allPropertyMetas,? CFRangeMake(0, modelMeta->_keyMappedCount), ModelSetWithPropertyMetaArrayFunction,? &context)方法賦值量没。

CFArrayApplyFunction對第一個數(shù)組類型的參數(shù)在第二個CFRange類型參數(shù)區(qū)間中遍歷玉转,沒遍歷一次調(diào)用一次第三個函數(shù)指針類型的參數(shù)指向的函數(shù),第四個參數(shù)為調(diào)用的函數(shù)的第二個參數(shù)殴蹄,每遍歷一次的數(shù)組元素為函數(shù)的第一個參數(shù)究抓。

可以看出第三個參數(shù)指向的函數(shù)式具體的對每一個屬性賦值的函數(shù),可展開來看:

就此袭灯,回到:

整個字典轉(zhuǎn)模型結(jié)束刺下。

之上就是一個字典轉(zhuǎn)模型的主干過程,整個過程還有很多細(xì)節(jié)都很贊妓蛮,整個框架在安全性和效率性兼顧做的確實(shí)很棒怠李,對于一些細(xì)節(jié),后邊再繼續(xù)探索蛤克。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末捺癞,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子构挤,更是在濱河造成了極大的恐慌髓介,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件筋现,死亡現(xiàn)場離奇詭異唐础,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)矾飞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進(jìn)店門一膨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人洒沦,你說我怎么就攤上這事豹绪。” “怎么了申眼?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵瞒津,是天一觀的道長。 經(jīng)常有香客問我括尸,道長巷蚪,這世上最難降的妖魔是什么损痰? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任罢缸,我火速辦了婚禮捧存,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘戳葵。我一直安慰自己燎孟,他們只是感情好喇勋,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布僚楞。 她就那樣靜靜地躺著,像睡著了一般似嗤。 火紅的嫁衣襯著肌膚如雪啸臀。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天烁落,我揣著相機(jī)與錄音乘粒,去河邊找鬼。 笑死伤塌,一個胖子當(dāng)著我的面吹牛灯萍,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播每聪,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼旦棉,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了药薯?” 一聲冷哼從身側(cè)響起绑洛,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎童本,沒想到半個月后真屯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡穷娱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年绑蔫,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片泵额。...
    茶點(diǎn)故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡配深,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出嫁盲,到底是詐尸還是另有隱情凉馆,我是刑警寧澤,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布亡资,位于F島的核電站,受9級特大地震影響向叉,放射性物質(zhì)發(fā)生泄漏锥腻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一母谎、第九天 我趴在偏房一處隱蔽的房頂上張望瘦黑。 院中可真熱鬧,春花似錦、人聲如沸幸斥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽甲葬。三九已至廊勃,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間经窖,已是汗流浹背坡垫。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留画侣,地道東北人冰悠。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像配乱,于是被迫代替她去往敵國和親溉卓。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 柳天殘是古裝武俠劇《八大豪俠》中的男性角色搬泥。他是世間少有的武學(xué)奇才桑寨,可以同時運(yùn)刀使劍,儼如天上神兵佑钾。 柳天殘自創(chuàng)了...
    柳育龍閱讀 169評論 0 0
  • 所謂惡習(xí)(è xí)西疤,就是壞習(xí)慣,每個人都有惡習(xí)休溶!吸煙代赁、喝酒、打麻將兽掰、賭博芭碍、花心、玩游戲等等都是或大或小孽尽,...
    淡定寶寶閱讀 750評論 1 0
  • 身為微商小白杉女,當(dāng)我們剛進(jìn)入微商行業(yè)瞻讽,常常是滿腔熱血地到處加好友。但好友加了一堆熏挎,更多的只是尋問并不購買速勇,產(chǎn)品始終賣...
    微小咖閱讀 298評論 0 0
  • 翻譯成《再次出發(fā)之紐約遇見你》真是夠了…… 話說這海報(bào)上真的看不出來是KK的側(cè)臉。 這個就切題多了坎拐,雖然不是很有特...
    水御龍神閱讀 429評論 1 1
  • 醒來的不合時宜呕乎,明明說今天會有雨,以為氣溫會降低一些陨晶,還是被熱醒猬仁。這個夏天的炎熱,空調(diào)好像都無濟(jì)于事珍逸。再入夢卻不找...
    風(fēng)阿塵閱讀 110評論 0 1