? ? 在日常的iOS開(kāi)發(fā)中饿幅,總會(huì)進(jìn)行數(shù)據(jù)的轉(zhuǎn)換险领,比如請(qǐng)求服務(wù)端獲取數(shù)據(jù)侨舆,解析數(shù)據(jù),轉(zhuǎn)換成對(duì)應(yīng)的model绢陌,這個(gè)轉(zhuǎn)換過(guò)程比較繁瑣挨下,重復(fù)工作較多,今天給大家介紹一個(gè)很好用的JSON轉(zhuǎn)換庫(kù)MJExtension脐湾。
? ? MJExtension是一套字典和模型之間互相轉(zhuǎn)換的超輕量級(jí)框架臭笆,利用runtime進(jìn)行數(shù)據(jù)之間的轉(zhuǎn)換,,使用簡(jiǎn)單無(wú)侵入,使用門(mén)檻較低愁铺,下面簡(jiǎn)單介紹下MJExtension的功能鹰霍。
MJExtension的功能介紹
下面是MJExtension的功能,包括將JSON --> Model茵乱,Dictionary -->Model茂洒,Model -->JSON,JSON Array --> Model Array 等等功能瓶竭。
JSON --> Model督勺、Core Data Model
JSONString --> Model、Core Data Model
Model斤贰、Core Data Model --> JSON
JSON Array --> Model Array玷氏、Core Data Model Array
JSONString --> Model Array、Core Data Model Array
Model Array腋舌、Core Data Model Array --> JSON Array
MJExtension的使用
在MJExtension中盏触,我們使用的api都在NSObject+MJKeyValue.h文件中,里面有詳細(xì)的注釋块饺,這里就不多說(shuō)了赞辩。下面我們就用微博的數(shù)據(jù)舉例子,進(jìn)行使用講解
1.簡(jiǎn)單的字典 -> 模型(模型中的屬性都是基本類型)
1)首先我們看下字典轉(zhuǎn)模型,只需要一行代碼就可以授艰,十分簡(jiǎn)潔方便辨嗽,這里需要注意下,model中的對(duì)應(yīng)屬性和字典中的key要相同淮腾,調(diào)用mj_objectWithKeyValues糟需。
2)假如我們覺(jué)得MJUser中的屬性命名有些歧義,不是很好谷朝,這時(shí)候我們想改一下洲押,比如字典中的name叫jack,可能對(duì)應(yīng)屬性叫firstname更好圆凰,這時(shí)候杈帐,我們就需要在字典轉(zhuǎn)模型的時(shí)候,進(jìn)行屬性名的替換专钉,我們可以這么做挑童,在MJUser.m文件中實(shí)現(xiàn)mj_replacedKeyFromPropertyName方法,方法如下圖所示跃须。
3)如果在轉(zhuǎn)換過(guò)程中站叼,我們只想對(duì)部分屬性,進(jìn)行轉(zhuǎn)換菇民,比如尽楔,你只需要firstname和icon投储,name可以使用如下方法進(jìn)行設(shè)置,mj_allowedPropertyNames或者mj_ignoredPropertyNames翔试,這兩個(gè)方法可以看做白名單和黑名單的方法轻要。
在MJUser.m文件中實(shí)現(xiàn)mj_allowedPropertyNames方法复旬,即可只轉(zhuǎn)換firstname和icon
4)如果在字典轉(zhuǎn)model的過(guò)程中垦缅,你需要改變firstname的值,在每個(gè) firstname前面加上一段文字驹碍,比如:“jack”變成我是“我的名字是jack”壁涎,這時(shí)候可以使用mj_newValueFromOldValue方法,下面在MJUser.m文件中實(shí)現(xiàn)mj_newValueFromOldValue方法志秃,每次進(jìn)行轉(zhuǎn)換的時(shí)候怔球,都可以在firstname前加上“我的名字是”,或者還可以做一些其它的處理浮还。
5)如果在字典轉(zhuǎn)換為model完成后竟坛,想做一些其它事情,可以使用mj_keyValuesDidFinishConvertingToObject方法進(jìn)行钧舌。
2.復(fù)雜的字典 -> 模型
? ? 除了上面的簡(jiǎn)單字典轉(zhuǎn)模型担汤,還有些復(fù)雜的模型,比如字典中包含字典和數(shù)組洼冻,這種情況崭歧,我們?cè)趺刺幚砟兀孔怖危浚?/p>
1)首先我們看一下率碾,下面這種數(shù)據(jù)結(jié)構(gòu),復(fù)雜的字典 -> 模型 (模型里面包含了模型)
這是一個(gè)字典嵌套字典的結(jié)構(gòu)屋彪,它需要轉(zhuǎn)成一個(gè)模型嵌套模型的結(jié)構(gòu)
只需要調(diào)用mj_objectWithKeyValues方法即可所宰,跟簡(jiǎn)單模型使用方法一致,其它都不需要我們做畜挥,至于模型嵌套模型這種結(jié)構(gòu)的轉(zhuǎn)換時(shí)怎么實(shí)現(xiàn)的歧匈,我會(huì)在下一部分,講解原理的時(shí)候說(shuō)到砰嘁。
2)下面我們看一下件炉,復(fù)雜的字典 -> 模型 (模型的數(shù)組屬性里面又裝著模型)
我們可以看到,上面MJStatusResult模型中的statuses屬性和ads屬性矮湘,都是一個(gè)array斟冕,而array中的每一個(gè)元素都是一個(gè)模型,比如statuses中是一個(gè)MJStatus模型缅阳,ads中是MJAd模型磕蛇,在進(jìn)行MJStatusResult模型的轉(zhuǎn)換過(guò)程中景描,我們需要設(shè)置數(shù)組屬性的模型的類型,這時(shí)候我們需要用到mj_objectClassInArray方法秀撇,指定數(shù)組屬性中元素的模型類型超棺,具體用法如下:
3.模型 -> 字典
模型轉(zhuǎn)字典主要有一下幾個(gè)方法呵燕,用法類似棠绘,這里就不多講了,大家可以看下源碼再扭。
MJExtension的原理
MJExtension中類說(shuō)明
在分析原理之前氧苍,我們先看下文件的MJExtension的文件組成,以及每個(gè)文件的作用泛范。
1.MJExtension.h 只是引用了一些頭文件让虐,方便管理。
2.MJExtensionConst.h和MJExtensionConst.m 聲明了一些宏定義罢荡,用來(lái)拋出異常和做判斷用的赡突,同時(shí)聲明和定義了一些屬性類型。
3.MJFoundation.h和MJFoundation.m文件主要是用來(lái)判斷某個(gè)類是否是來(lái)自Foundation庫(kù)中的基本類型区赵,在進(jìn)行字典和模型的轉(zhuǎn)換過(guò)程中惭缰,會(huì)根據(jù)這個(gè)類來(lái)判斷是否是模型嵌套模型的結(jié)構(gòu)。
4.MJProperty.h和MJProperty.m是一個(gè)記錄屬性信息的類惧笛,包含屬性的的所有信息从媚,比如,屬性類型患整,名字拜效,來(lái)源等等。
5.MJPropertyKey.h和MJPropertyKey.m提供一個(gè)根據(jù)屬性key各谚,返回屬性值的方法紧憾。
6.MJPropertyType.h和MJPropertyType.m是記錄一個(gè)屬性的類型,比如MJProperty中屬性類型就是用MJPropertyType來(lái)記錄的昌渤,MJPropertyType類中包含類型標(biāo)識(shí)符赴穗,是否為基本數(shù)字類型,來(lái)源框架膀息,是否支持KVC等等般眉,在字典和模型轉(zhuǎn)換中,提供屬性類型信息潜支。
7.NSObject+MJClass.h和NSObject+MJClass.m用來(lái)遍歷所有類甸赃,并進(jìn)行黑名單和白名單的管理。
8.NSObject+MJCoding.h和NSObject+MJCoding.m主要是對(duì)屬性值進(jìn)行歸檔和解檔冗酿,并且可以對(duì)屬性名字添加黑名單和白名單埠对。
9.NSObject+MJKeyValue.h和NSObject+MJKeyValue.m類中提供了所有模型和字典之間轉(zhuǎn)換的接口络断,上面講的使用方法,都是來(lái)自與這個(gè)類的接口项玛,我們需要熟悉里面的所有接口貌笨,以便可以更好的使用它。
10.NSObject+MJProperty.h和NSObject+MJProperty.m是遍歷模型所有成員襟沮,獲取模型中的屬性锥惋,用MJProperty類保存屬性,用于進(jìn)行字典和模型轉(zhuǎn)換臣嚣。
11.NSString+MJExtension.h和NSString+MJExtension.m是用來(lái)進(jìn)行屬性名字轉(zhuǎn)換的類净刮,比如講駝峰格式的類名剥哑,轉(zhuǎn)換為下劃線的命名格式硅则。
MJExtension模型字典轉(zhuǎn)換過(guò)程
1.使用runtime 獲取模型的所有屬性 ,轉(zhuǎn)換成MJProperty屬性模型列表
2.根據(jù)MJProperty中的屬性類型株婴,對(duì)屬性進(jìn)行處理怎虫,獲取屬性值。
3. 根據(jù)屬性名字困介,通過(guò)KVC對(duì)屬性賦值大审。
1.runtime如何獲取所有屬性
首先我們看下MJExtension的源碼,NSObject+MJProperty類中的+ (NSMutableArray *)properties方法座哩。
1)首先使用runtime中的class_copyPropertyList方法徒扶,獲取類的所有屬性,class_copyPropertyList方法會(huì)返回一個(gè)objc_property_t類型的對(duì)象,這是一個(gè)結(jié)構(gòu)體根穷,如下所示
objc_property是一個(gè)結(jié)構(gòu)體姜骡,是一個(gè)內(nèi)置的類型,與之關(guān)聯(lián)的還有一個(gè)objc_property_attribute_t屿良,它是屬性的attribute圈澈,也就是其實(shí)是對(duì)屬性的詳細(xì)描述,包括屬性名稱尘惧、屬性編碼類型康栈、原子類型/非原子類型等。它的定義如下:
2)然后遍歷每個(gè)成員喷橙,將objc_property_t中的屬性啥么,轉(zhuǎn)換成MJProperty對(duì)象,轉(zhuǎn)換過(guò)程如下:
首先使用property_getName獲取屬性名贰逾,然后使用property_getAttributes獲取objc_property_attribute_t悬荣,為一個(gè)字符串的結(jié)果,里面包含屬性名稱似踱、屬性編碼類型隅熙、原子類型/非原子類型等稽煤,比如:NSString類型的屬性,對(duì)應(yīng)的attrs為T(mén)@"NSString",C,N,V_icon囚戚。下面我解釋一下這個(gè)字符串對(duì)應(yīng)的意思:
T 表示屬性的類型 類型為基本對(duì)象類型和基本數(shù)據(jù)類型酵熙,基本對(duì)象類型的value為該對(duì)象類型名字 如NSArray、NSString驰坊、NSMutableDictionary 等
C 表示該屬性為copy 匾二;為&表示屬性為strong;W表示屬性為weak拳芙;空 表示屬性為assgin
N表示為非原子屬性
V表示屬性的名字 此時(shí)value為加了下劃線的屬性名字
最后會(huì)根據(jù)property_getAttributes信息生成屬性對(duì)象的type察藐。
2.根據(jù)MJProperty中的屬性類型,對(duì)屬性進(jìn)行處理舟扎,獲取屬性值分飞。
根據(jù)屬性類型,對(duì)屬性進(jìn)行處理主要在- (instancetype)mj_setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context 方法中進(jìn)行的睹限,如下所示:
從上面代碼可以看出
1)通過(guò)valueInObject獲取屬性值value譬猫,
2)獲取到值以后,做了一些特殊處理
將value由可變對(duì)象轉(zhuǎn)換成不可變類型
如果value是模型羡疗,則繼續(xù)將value轉(zhuǎn)換成模型染服。
如果模型類型是NSString類型,會(huì)將屬性類型中的NSNumber和NSURL轉(zhuǎn)換為NSString叨恨。
如果模型類型是NSURL類型柳刮,會(huì)將屬性類型中NSString轉(zhuǎn)換為NSURL。
如果模型類型是NSNumber類型痒钝,會(huì)將屬性類型中NSString轉(zhuǎn)換為NSNumber秉颗。
如果模型類型是NSNumber類型,會(huì)將屬性類型中NSString轉(zhuǎn)換為NSNumber午乓。
如果模型類型是BOOL類型站宗,會(huì)將字符串和yes,true益愈,no梢灭,false進(jìn)行匹配,轉(zhuǎn)換為BOOL類型
如果模型類型和屬性類型不匹配蒸其,會(huì)將value設(shè)置為nil敏释。
3. 根據(jù)屬性名字,通過(guò)KVC對(duì)屬性賦值摸袁。
接下來(lái)钥顽,會(huì)使用屬性值value,為屬性賦值靠汁,如下所示:
首先會(huì)判斷是否支持KVC蜂大,如果支持會(huì)給屬性賦值闽铐。
到這里就講解完了MJExtension的使用和原理