字典轉(zhuǎn)模型之KVC和MJExtension底層的實(shí)現(xiàn)

一 快速生成@property

1 當(dāng)我們需要用模型去實(shí)現(xiàn)一個(gè)比較小的功能的時(shí)候,由于我們需要對(duì)plist文件進(jìn)行轉(zhuǎn)化成模型,那么很有可能我們拿到的plist文件中的屬性很多,但是我們又因?yàn)橹恍枰芯恳粋€(gè)很小的功能,那么我們可以不需要將plist文件中的數(shù)據(jù)全部轉(zhuǎn)化為模型數(shù)據(jù),我們只需要提取其中的一部分用來(lái)實(shí)現(xiàn)模型就可以,那么我們?cè)趺醋瞿?

2 做法:展開(kāi)某行,然后拷貝該行的item,然后將所有的item折起來(lái),在將拷貝的東西復(fù)制到root上即可直接將一整個(gè)plist文件改為自己需要處理的文件,用該文件去處理一項(xiàng)特別小的功能.

3 但是由于plist文件中屬性太多,如果我們要?jiǎng)?chuàng)建一個(gè)模型,那么不得不寫這么多屬性,首先寫這些屬性都是無(wú)用功,沒(méi)什么技術(shù)含量,那么我們就想,有沒(méi)有什么辦法,可以一次性生成寫好的屬性,或者我們直接拷貝就可以了.那么,我們就想到了一個(gè)方法,通過(guò)一個(gè)方法,可以快速的將plist文件中的屬性生成@property的格式,我們只需要將結(jié)果拷貝,往@interface中粘貼就可以了.

4 代碼(通過(guò)一個(gè)分類就可以達(dá)到效果,如果需要就直接將分類拷貝到項(xiàng)目中就可以)

//快速生成@property屬性

- (void)creatPropetyCode

{

//創(chuàng)建可變的字符串

NSMutableString*codes = [NSMutableStringstring];

//由于plist文件外層都是字典,那么我們就遍歷字典

[selfenumerateKeysAndObjectsUsingBlock:^(id_Nonnull key,id_Nonnull value,BOOL* _Nonnull stop) {

//初始化變量,用來(lái)接收字符串的

NSString*code =nil;

//打印所有的value的類型,就知道BOOL到底是什么類型了.

//2016-03-26 23:06:50.867 03-RunTime(字典轉(zhuǎn)模型)[853:40171] __NSCFBoolean

NSLog(@"%@",[value class]);

//判斷value的類型,然后響應(yīng)的憑借出不同類類型的字符串,滿足模型中定義屬性的需求

if([value isKindOfClass:[NSStringclass]]) {

code = [NSStringstringWithFormat:@"@property (nonatomic, strong) NSString *%@;",key];

}elseif([value isKindOfClass:NSClassFromString(@"__NSCFBoolean")]){

code = [NSStringstringWithFormat:@"@property (nonatomic, strong) BOOL *%@;",key];

}elseif([value isKindOfClass:[NSNumberclass]]){

code = [NSStringstringWithFormat:@"@property (nonatomic, strong) NSNumber *%@;",key];

}elseif([value isKindOfClass:[NSDictionaryclass]]){

code = [NSStringstringWithFormat:@"@property (nonatomic, strong) NSDictionary *%@;",key];

}elseif([value isKindOfClass:[NSArrayclass]]){

code = [NSStringstringWithFormat:@"@property (nonatomic, strong) NSArray *%@;",key];

}

//拼接字符串

[codes appendFormat:@"\n%@\n",code];

}];

//打印出結(jié)果

NSLog(@"%@",codes);

}

//從打印的結(jié)果來(lái)看,大部分的都能打印出來(lái),但是類型是BOOL的卻打印不出來(lái),我們也沒(méi)法通過(guò)判斷BOOL的類型來(lái)打印,因?yàn)锽OOL就不是一個(gè)類.所以我們必須得想法辦知道BOOL的類型.


二 KVC底層實(shí)現(xiàn)

1 模型中的KVC方法

//KVC

[statusItem setValuesForKeysWithDictionary:dict];


2 問(wèn)題:KVC底層是怎么實(shí)現(xiàn)通過(guò)字典對(duì)模型中的屬性賦值?

2.1 首先我么要明確KVC的使用條件:KVC的使用,必須要保證模型中的屬性名要和字典中的key一一對(duì)應(yīng),否則使用KVC運(yùn)行時(shí)會(huì)報(bào)錯(cuò)的.

2.2 setValuesForKeysWithDictionary:該方法本質(zhì)其實(shí)就是遍歷字典中所有的key,去模型中查找對(duì)應(yīng)的屬性,把值給模型屬性賦值

3 setValuesForKeysWithDictionary:該方法的底層實(shí)現(xiàn)原理:

//遍歷

[dict enumerateKeysAndObjectsUsingBlock:^(id_Nonnull key,id_Nonnull obj,BOOL* _Nonnull stop) {

//這行代碼才是真正給模型的屬性賦值

[s setValue:dict[@"source"] forKey:@"source"];

}];


4 遍歷字典的內(nèi)部給屬性賦值遵循下面幾點(diǎn)條件

/*

[ssetValue:dict[@"source"]forKey:@"source"];

1.首先會(huì)去模型中查找有沒(méi)有setSource方法,直接調(diào)用set方法[ssetSource:dict[@"source"]];

2.去模型中查找有沒(méi)有source屬性,source= dict[@"source"]

3.去模型中查找有沒(méi)有_source屬性,_source= dict[@"source"]

4.調(diào)用對(duì)象的setValue:forUndefinedKey:直接報(bào)錯(cuò)

*/

5 很多時(shí)候我們不需要plist文件中的所有的屬性都有作用,但是我們又想用kvc來(lái)實(shí)現(xiàn)給模型屬性賦值,那么我們有什么辦法呢?

5.1 由于我們都知道,如果在plist文件中的屬性和模型中的屬性并不是一一對(duì)應(yīng)的關(guān)系,但是如果我們用KVC運(yùn)行起來(lái)會(huì)直接報(bào)錯(cuò),打印出錯(cuò)誤的結(jié)果是:setValue: forUndefinedKey:那么我們是不是想辦法不讓這錯(cuò)誤提示出來(lái)呢.那么我們可以重寫系統(tǒng)的這個(gè)方法,里面什么都不需要做.這樣同樣能達(dá)到目的.

-(void)setValue:(id)value forUndefinedKey:(NSString *)key

{



三 MJExtension框架的底層實(shí)現(xiàn)(一級(jí)轉(zhuǎn)化)

MJ框架與KVC的底層實(shí)現(xiàn)不同點(diǎn):

1 KVC是通過(guò)遍歷字典中的所有key,然后去模型中尋找對(duì)應(yīng)的屬性

2 MJ框架是通過(guò)先遍歷模型中的屬性,然后去字典中尋找對(duì)應(yīng)的key,所以用MJ框架的時(shí)候,模型中的屬性和字典可以不用一一對(duì)應(yīng),同樣能達(dá)到給模型賦值的效果.

3 代碼:

//返回一個(gè)創(chuàng)建好的模型

+ (instancetype)modelWithDict:(NSDictionary*)dict

{

//創(chuàng)建一個(gè)模型

idobjc = [[selfalloc] init];

intcount =0;

/*

方法:獲取成員變量列表

參數(shù)一:class獲取哪個(gè)類成員變量列表

參數(shù)二:count成員變量總數(shù)

*/

//成員變量數(shù)組指向數(shù)組第0個(gè)元素

Ivar *ivarList = class_copyIvarList(self, &count);

//遍歷所有成員變量

for(inti =0; i < count; i++) {

//獲取成員變量

Ivar ivar = ivarList[i];

//獲取成員變量名稱(將c轉(zhuǎn)為oc)

NSString*ivarName = [NSStringstringWithUTF8String:ivar_getName(ivar)];

//成員變量名稱轉(zhuǎn)換key(將成員變量前邊的"_"截取掉)

NSString*key = [ivarName substringFromIndex:1];

//從字典中取出對(duì)應(yīng)value

idvalue = dict[key];

//給模型中屬性賦值(底層會(huì)去找對(duì)應(yīng)的屬性和值)

[objc setValue:value forKey:key];

}

returnobjc;

}

四 附加知識(shí)點(diǎn)

1 const與宏的區(qū)別

1.1 編譯的時(shí)刻不一樣: 宏:預(yù)編譯 const:編譯

1.2 編譯檢查:宏不會(huì)做編譯檢查 const會(huì)

1.3 宏的好處:宏可以定義函數(shù)和方法 const不可以

1.4 宏壞處:大量使用宏,會(huì)導(dǎo)致預(yù)編譯時(shí)間過(guò)長(zhǎng)

2 const作用

2.1 用于修飾右邊變量(基本變量,指針變量)

2.2 被const修飾變量只讀

2.3 有關(guān)const的面試題

int*constp1;// p1:只讀*p1:變量

constint*p2;// p2:變量*p2:只讀

intconst*p3;// p3:變量*p3:只讀

intconst*constp4;// p4:只讀*p4:只讀

constint*constp5;// p5:只讀*p5:只讀


3 const在開(kāi)發(fā)當(dāng)中的使用

3.1 const替換宏,宏:常用字符串或者基本數(shù)據(jù)定義成宏 -> const

3.2 修飾方法參數(shù),讓方法參數(shù)只讀

4 static和extern

4.1 static:

—–>1> 修飾局部變量,只要被static修飾局部變量,這個(gè)局部變量的聲明周期就會(huì)延長(zhǎng)(整個(gè)app運(yùn)行過(guò)程中都在),作用域不變

—–>2> 修飾全局變量,只要被static修飾全局變量,這個(gè)全局變量只能在當(dāng)前文件下使用

—–>3> 分配時(shí)刻:程序一運(yùn)行的時(shí)候就會(huì)分配內(nèi)存

4.2 extern:

—–>1> 僅僅只用來(lái)聲明外部全局變量

—–>2> extern不能用來(lái)定義變量

5 static和const聯(lián)合使用

5.1 被static修飾全局變量,全局變量只能在當(dāng)前文件下使用

5.2 被const修飾,只讀.

6 開(kāi)發(fā)中是如何避免重復(fù)定義?

做法:只要定義全局變量,都不能再自己的類中定義,一般開(kāi)發(fā)中,我們會(huì)搞一個(gè)公共的文件來(lái)定義全局變量

五 總結(jié)

以上就是今天我給大家分享的知識(shí)點(diǎn),很多知識(shí)點(diǎn)都寫得很詳細(xì)了,如果有不懂的可以給我留言,謝謝.我明天還會(huì)持續(xù)更新新的知識(shí)點(diǎn).記得關(guān)注哦!!!

Baidu Button BEGIN

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末羽峰,一起剝皮案震驚了整個(gè)濱河市虫溜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,366評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件揪垄,死亡現(xiàn)場(chǎng)離奇詭異矛市,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)车遂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)斯辰,“玉大人舶担,你說(shuō)我怎么就攤上這事”蛏耄” “怎么了衣陶?”我有些...
    開(kāi)封第一講書人閱讀 165,689評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)闸氮。 經(jīng)常有香客問(wèn)我剪况,道長(zhǎng),這世上最難降的妖魔是什么蒲跨? 我笑而不...
    開(kāi)封第一講書人閱讀 58,925評(píng)論 1 295
  • 正文 為了忘掉前任译断,我火速辦了婚禮,結(jié)果婚禮上或悲,老公的妹妹穿的比我還像新娘孙咪。我一直安慰自己堪唐,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布翎蹈。 她就那樣靜靜地躺著淮菠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪荤堪。 梳的紋絲不亂的頭發(fā)上合陵,一...
    開(kāi)封第一講書人閱讀 51,727評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音澄阳,去河邊找鬼拥知。 笑死,一個(gè)胖子當(dāng)著我的面吹牛寇荧,可吹牛的內(nèi)容都是我干的举庶。 我是一名探鬼主播,決...
    沈念sama閱讀 40,447評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼揩抡,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼户侥!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起峦嗤,我...
    開(kāi)封第一講書人閱讀 39,349評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蕊唐,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后烁设,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體替梨,經(jīng)...
    沈念sama閱讀 45,820評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評(píng)論 3 337
  • 正文 我和宋清朗相戀三年装黑,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了副瀑。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,127評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡恋谭,死狀恐怖糠睡,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情疚颊,我是刑警寧澤狈孔,帶...
    沈念sama閱讀 35,812評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站材义,受9級(jí)特大地震影響均抽,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜其掂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評(píng)論 3 331
  • 文/蒙蒙 一油挥、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦喘漏、人聲如沸护蝶。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,017評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至盔夜,卻和暖如春负饲,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背喂链。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,142評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工返十, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人椭微。 一個(gè)月前我還...
    沈念sama閱讀 48,388評(píng)論 3 373
  • 正文 我出身青樓洞坑,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親蝇率。 傳聞我的和親對(duì)象是個(gè)殘疾皇子迟杂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評(píng)論 2 355

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