版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
【移動(dòng)應(yīng)用開發(fā)技術(shù)】從YYModel源碼中可以學(xué)到什么:后篇
上一篇中《從YYModel源碼中可以學(xué)到什么:后篇》中主要學(xué)習(xí)了YYModel的源碼結(jié)構(gòu),只是分享了YYModel整體結(jié)構(gòu)。承接上篇,本文將解讀YYModel如何進(jìn)行JSON模型轉(zhuǎn)換的,接下來(lái)一起揭開YYModel的神秘面紗吧!首先來(lái)看JSON是如何轉(zhuǎn)為Model。查看YYModel的接口,提供了一個(gè)方法:+(instancetype)yy_modelWithJSON:(id)json;注意json為id類型,接收三種不同類型參數(shù)NSString,NSData,NSDictionay。下面是內(nèi)部實(shí)現(xiàn):+(instancetype)yy_modelWithJSON:(id)json{
NSDictionary*dic=[self_yy_dictionaryWithJSON:json];
return[selfyy_modelWithDictionary:dic];
}方法中調(diào)用了一個(gè)私有方法_yy_dictionaryWithJSON:,該方法將id類型的json(NSDictionary,NSString,NSData)轉(zhuǎn)為字典。+(NSDictionary*)_yy_dictionaryWithJSON:(id)json{
//驗(yàn)證json
if(!json||json==(id)kCFNull)returnnil;
//兩個(gè)臨時(shí)變量
NSDictionary*dic=nil;
NSData*jsonData=nil;
//根據(jù)json類型,進(jìn)行相應(yīng)處理
if([jsonisKindOfClass:[NSDictionaryclass]]){
dic=json;
}elseif([jsonisKindOfClass:[NSStringclass]]){
jsonData=[(NSString*)jsondataUsingEncoding:NSUTF8StringEncoding];
}elseif([jsonisKindOfClass:[NSDataclass]]){
jsonData=json;
}
//使用NSJSONSerialization將Data轉(zhuǎn)為字典
if(jsonData){
dic=[NSJSONSerializationJSONObjectWithData:jsonDataoptions:kNilOptionserror:NULL];
if(![dicisKindOfClass:[NSDictionaryclass]])dic=nil;
}
returndic;
}
該方法很簡(jiǎn)單,就是判斷id類型是指(NSDictionary,NSString,NSData)中的哪一個(gè),分別處理。
在json==(id)kCFNull中kCFNull是什么意思?這條語(yǔ)句起到什么作用?
nil:指向OC中對(duì)象的空指針
Nil:指向OC中類的空指針
NULL:定義其他類型(基本類型、C類型)的空指針
NSNull:集合對(duì)象中,表示空值的對(duì)象。如給數(shù)組設(shè)置空值,使用NSNull,而不能使用nil。
kCFNull是NSNull的單例。
if(!json||json==(id)kCFNull)returnnil;該判斷的意思是,json對(duì)象不存在,或者為空是返回nil。
該方法很簡(jiǎn)單,就是判斷id類型是指(NSDictionary,NSString,NSData)中的哪一個(gè),分別處理。在json==(id)kCFNull中kCFNull是什么意思?這條語(yǔ)句起到什么作用?nil:指向OC中對(duì)象的空指針Nil:指向OC中類的空指針NULL:定義其他類型(基本類型、C類型)的空指針NSNull:集合對(duì)象中,表示空值的對(duì)象。如給數(shù)組設(shè)置空值,使用NSNull,而不能使用nil。kCFNull是NSNull的單例。if(!json||json==(id)kCFNull)returnnil;該判斷的意思是,json對(duì)象不存在,或者為空是返回nil。獲取到字典后,調(diào)用字典轉(zhuǎn)Model方法:+(nullableinstancetype)yy_modelWithDictionary:(NSDictionary*)dictionary此方法也是在.h文件中暴露出來(lái)的方法。接下來(lái)查看具體實(shí)現(xiàn):/**
字典轉(zhuǎn)model
@paramdictionary字典
@return返回Model對(duì)象
*/
+(instancetype)yy_modelWithDictionary:(NSDictionary*)dictionary{
//1.驗(yàn)證,空值,nil和是否是字典
if(!dictionary||dictionary==(id)kCFNull)returnnil;
if(![dictionaryisKindOfClass:[NSDictionaryclass]])returnnil;
Classcls=[selfclass];
//2.創(chuàng)建一個(gè)YYModelMeta對(duì)象
_YYModelMeta*modelMeta=[_YYModelMetametaWithClass:cls];
//判斷是否需要自定義返回模型的類型,這是YYModel協(xié)議中的內(nèi)容,算是附加功能暫時(shí)先忽略,后面在介紹。
if(modelMeta->_hasCustomClassFromDictionary){
cls=[clsmodelCustomClassForDictionary:dictionary]?:cls;
}
//3.創(chuàng)建model對(duì)象
NSObject*one=[clsnew];
//4.關(guān)鍵方法
if([oneyy_modelSetWithDictionary:dictionary])
returnone;
returnnil;
}這個(gè)方法主要的任務(wù)是調(diào)用了yy_modelSetWithDictionary:方法。這個(gè)方法也是在.h文件中暴露的,它的作用是根據(jù)字典初始化模型。代碼實(shí)現(xiàn):-(BOOL)yy_modelSetWithDictionary:(NSDictionary*)dic{
//1.值和類型驗(yàn)證
if(!dic||dic==(id)kCFNull)returnNO;
if(![dicisKindOfClass:[NSDictionaryclass]])returnNO;
//2.創(chuàng)建Modelmeta對(duì)象
_YYModelMeta*modelMeta=[_YYModelMetametaWithClass:object_getClass(self)];
//屬性個(gè)數(shù),如為零返回。創(chuàng)建失敗
if(modelMeta->_keyMappedCount==0)returnNO;
//YYModel協(xié)議,暫且忽略
if(modelMeta->_hasCustomWillTransformFromDictionary){
dic=[((id<YYModel>)self)modelCustomWillTransformFromDictionary:dic];
if(![dicisKindOfClass:[NSDictionaryclass]])returnNO;
}
//3.創(chuàng)建結(jié)構(gòu)體
ModelSetContextcontext={0};
context.modelMeta=(__bridgevoid*)(modelMeta);
context.model=(__bridgevoid*)(self);
context.dictionary=(__bridgevoid*)(dic);
//模型元值數(shù)量和字典數(shù)量關(guān)系
//1.通常情況是兩者相等,
//2.模型元鍵值少于字典個(gè)數(shù)
if(modelMeta->_keyMappedCount>=CFDictionaryGetCount((CFDictionaryRef)dic)){
//調(diào)用ModelSetWithDictionaryFunction方法,這是核心方法。
//參數(shù):
//1.要操作的字典
//2.為每個(gè)鍵值對(duì)調(diào)用一次的回調(diào)函數(shù)
//3.指針大小的程序定義的值,作為第三個(gè)參數(shù)傳遞給應(yīng)用程序函數(shù),但此函數(shù)未使用該值.與參數(shù)2適應(yīng)
CFDictionaryApplyFunction((CFDictionaryRef)dic,ModelSetWithDictionaryFunction,&context);
//是否存在映射keyPath屬性元
if(modelMeta->_keyPathPropertyMetas){
//每個(gè)keypath都執(zhí)行ModelSetWithPropertyMetaArrayFunction
CFArrayApplyFunction((CFArrayRef)modelMeta->_keyPathPropertyMetas,
CFRangeMake(0,CFArrayGetCount((CFArrayRef)modelMeta->_keyPathPropertyMetas)),
ModelSetWithPropertyMetaArrayFunction,
&context);
}
//是否存在映射多個(gè)key的屬性元
if(modelMeta->_multiKeysPropertyMetas){
//每個(gè)keypath都執(zhí)行ModelSetWithPropertyMetaArrayFunction
CFArrayApplyFunction((CFArrayRef)modelMeta->_multiKeysPropertyMetas,
CFRangeMake(0,CFArrayGetCount((CFArrayRef)modelMeta->_multiKeysPropertyMetas)),
ModelSetWithPropertyMetaArrayFunction,
&context);
}
}else{
//每個(gè)keypath都執(zhí)行ModelSetWithPropertyMetaArrayFunction
CFArrayApplyFunction((CFArrayRef)modelMeta->_allPropertyMetas,
CFRangeMake(0,modelMeta->_keyMappedCount),
ModelSetWithPropertyMetaArrayFunction,
&context);
}
//忽略
if(modelMeta->_hasCustomTransformFromDictionary){
return[((id<YYModel>)self)modelCustomTransformFromDictionary:dic];
}
returnYES;
}
上面注釋該方法大致干了幾件事。關(guān)于ModelSetContext是一個(gè)結(jié)構(gòu)體。包含模型元,模型實(shí)例和待處理字典。typedefstruct{
void*modelMeta;///<_YYModelMeta
void*model;///<id(self)
void*dictionary;///<NSDictionary(json)
}ModelSetContext;通過上面的分析,線路越來(lái)越清晰,下面看一下核心方法ModelSetWithDictionaryFunction將字典的鍵值對(duì)取出賦值給Model。//獲取到字典的鍵值對(duì),和上下文信息。
staticvoidModelSetWithDictionaryFunction(constvoid*_key,constvoid*_value,void*_context){
//上下文,包含模型元,模型實(shí)例,字典
ModelSetContext*context=_context;
//模型元
__unsafe_unretained_YYModelMeta*meta=(__bridge_YYModelMeta*)(context->modelMeta);
//在模型元屬性字典中查找鍵值為key的屬性
__unsafe_unretained_YYModelPropertyMeta*propertyMeta=[meta->_mapperobjectForKey:(__bridgeid)(_key)];
//模型實(shí)例
__unsafe_unretainedidmodel=(__bridgeid)(context->model);
//核心內(nèi)容,遍歷所有的屬性元。知道_next=nil
while(propertyMeta){
if(propertyMeta->_setter){
//最終轉(zhuǎn)換(高潮)
ModelSetValueForProperty(model,(__bridge__unsafe_unretainedid)_value,propertyMeta);
}
propertyMeta=propertyMeta->_next;
};
}該方法主要任務(wù)是,遍歷所有的屬性元,調(diào)用模型屬性賦值方法ModelSetValueForProperty。最終實(shí)現(xiàn)。也就是YYModel的最最最核心的部分。不過,這個(gè)方法長(zhǎng)的離譜。由于涉及到較多的編碼類型,需要對(duì)不同的類型區(qū)分處理,導(dǎo)致代碼過長(zhǎng)。由于ModelSetValueForPorperty代碼較長(zhǎng),這里不再?gòu)?fù)制代碼。只梳理一下實(shí)現(xiàn)的邏輯,注釋代碼在Github自行查閱。調(diào)用ModelSetNumberToPorperty方法,該方法作用是:識(shí)別null、bool、123.
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 《時(shí)尚北京》雜志26年2月份
- 中學(xué)安全管理與防護(hù)制度
- 企業(yè)員工培訓(xùn)與能力建設(shè)制度
- 交通設(shè)施維護(hù)保養(yǎng)規(guī)范制度
- 2026年市場(chǎng)營(yíng)銷策略案例分析練習(xí)題
- 2026年物流與供應(yīng)鏈管理優(yōu)化題庫(kù)
- 2026年國(guó)際漢語(yǔ)教師資格考試文化知識(shí)與教學(xué)技能題庫(kù)
- 2026年CPA注冊(cè)會(huì)計(jì)師綜合試題庫(kù)及解析
- 2026年振蕩培養(yǎng)協(xié)議
- 古典概型課件
- 2025中國(guó)胸痛中心診療指南
- 藥品抽檢應(yīng)急預(yù)案(3篇)
- ADC藥物首次人體試驗(yàn)劑量遞推
- 醫(yī)藥行業(yè)2026年度醫(yī)療器械策略報(bào)告耗材IVD篇:創(chuàng)新引領(lǐng)國(guó)際布局后集采時(shí)代醫(yī)療器械的價(jià)值重構(gòu)
- 收購(gòu)酒店合同怎么寫模板(3篇)
- 新生兒死亡評(píng)審管理制度
- 酒店餐飲食品安全管理手冊(cè)
- DB2110∕T 0004-2020 遼陽(yáng)地區(qū)主要樹種一元、二元立木材積表
- 電信崗位晉升管理辦法
- 業(yè)務(wù)提成協(xié)議勞務(wù)合同
- T-FIQ 003-2025 青海省可持續(xù)掛鉤貸款服務(wù)指南
評(píng)論
0/150
提交評(píng)論