一篇文章全吃透—史上最全YYModel的使用詳解

開篇說明:
雖然網(wǎng)上有很多講解YYModel使用方法的文章胰默,包括YYModel作者也在github上對其做了使用說明。
但在我實(shí)際使用過程中,依然發(fā)現(xiàn)文檔的不完善,比如對于復(fù)雜的模型(如多層嵌套)講解的仍不透徹瓦宜,同時本文也會介紹一神器配合YYModel使用,讓你感受分分鐘搞定模型創(chuàng)建的酸爽岭妖。
當(dāng)然為了減少讀者的學(xué)習(xí)成本临庇,本會對YYModel作者的文檔進(jìn)行豐富和擴(kuò)展反璃。
可在github上下載Demo,以便更直觀了解各種使用場景詳細(xì)代碼假夺。
文章只要包含:

    1. 詳解YYModel的多種使用場景
    1. 拓展插件淮蜈,讓你一分鐘搞定所有的模型的創(chuàng)建和調(diào)用。

一已卷、YYModel的使用場景

1.簡單的 Model 與 JSON 相互轉(zhuǎn)換

// JSON:
{
    "uid":123456,
    "name":"Harry",
    "created":"1965-07-31T00:00:00+0000"
}

// Model:
@interface User : NSObject
@property UInt64 uid;
@property NSString *name;
@property NSDate *created;
@end

@implementation User

@end
// 將 JSON (NSData,NSString,NSDictionary) 轉(zhuǎn)換為 Model:
User *user = [User yy_modelWithJSON:json];

// 將 Model 轉(zhuǎn)換為 JSON 對象:
NSDictionary *json = [user yy_modelToJSONObject];

JSON/Dictionary 中的對象類型與 Model 屬性不一致時梧田,YYModel 將會進(jìn)行如下自動轉(zhuǎn)換。自動轉(zhuǎn)換不支持的值將會被忽略侧蘸,以避免各種潛在的崩潰問題裁眯。


格式自動轉(zhuǎn)換.png

2.Model 屬性名和 JSON 中的 Key 不相同

// JSON:
{
    "n":"Harry Pottery",
    "p": 256,
    "ext" : {
        "desc" : "A book written by J.K.Rowing."
    },
    "ID" : 100010
}

// Model:
@interface Book : NSObject
@property NSString *name;
@property NSInteger page;
@property NSString *desc;
@property NSString *bookID;
@end
@implementation Book
//返回一個 Dict,將 Model 屬性名對映射到 JSON 的 Key讳癌。
+ (NSDictionary *)modelCustomPropertyMapper {
    return @{@"name" : @"n",
             @"page" : @"p",
             @"desc" : @"ext.desc",
             @"bookID" : @[@"id",@"ID",@"book_id"]};
}
@end

你可以把一個或一組 json key (key path) 映射到一個或多個屬性穿稳。如果一個屬性沒有映射關(guān)系,那默認(rèn)會使用相同屬性名作為映射析桥。
在 json->model 的過程中:如果一個屬性對應(yīng)了多個 json key司草,那么轉(zhuǎn)換過程會按順序查找,并使用第一個不為空的值泡仗。
在 model->json 的過程中:如果一個屬性對應(yīng)了多個 json key (key path)埋虹,那么轉(zhuǎn)換過程僅會處理第一個 json key (key path);如果多個屬性對應(yīng)了同一個 json key娩怎,則轉(zhuǎn)換過過程會使用其中任意一個不為空的值搔课。

3.Model 包含其他 Model

// JSON
{
    "author":{
        "name":"J.K.Rowling",
        "birthday":"1965-07-31T00:00:00+0000"
    },
    "name":"Harry Potter",
    "pages":256
}

// Model: 什么都不用做,轉(zhuǎn)換會自動完成
@interface Author : NSObject
@property NSString *name;
@property NSDate *birthday;
@end
@implementation Author
@end

@interface Book : NSObject
@property NSString *name;
@property NSUInteger pages;
@property Author *author; //Book 包含 Author 屬性
@end
@implementation Book
@end

4.容器類屬性

@class Shadow, Border, Attachment;

@interface Attributes
@property NSString *name;
@property NSArray *shadows; //Array<Shadow>
@property NSSet *borders; //Set<Border>
@property NSMutableDictionary *attachments; //Dict<NSString,Attachment>
@end

@implementation Attributes
// 返回容器類中的所需要存放的數(shù)據(jù)類型 (以 Class 或 Class Name 的形式)截亦。
+ (NSDictionary *)modelContainerPropertyGenericClass {
    return @{@"shadows" : [Shadow class],
             @"borders" : Border.class,
             @"attachments" : @"Attachment" };
}
@end

在實(shí)際使用過過程中爬泥,[Shadow class]Border.class崩瓤,@"Attachment"沒有明顯的區(qū)別袍啡。
這里僅僅是創(chuàng)建作者有說明,實(shí)際使用時却桶,需要對其遍歷境输,取出容器中得字典,然后繼續(xù)字典轉(zhuǎn)模型颖系。(YYModel的核心是通過runtime獲取結(jié)構(gòu)體中得Ivars的值嗅剖,將此值定義為key,然后給keyvalue值嘁扼,所以我們需要自己遍歷容器(NSArray信粮,NSSetNSDictionary)趁啸,獲取每一個值强缘,通過objc_msgSend動態(tài)調(diào)用對象的set方法給屬性賦值)督惰。

  • 具體的代碼實(shí)現(xiàn)如下:
NSDictionary *json =[self getJsonWithJsonName:@"ContainerModel"];
ContainerModel *containModel = [ContainerModel yy_modelWithDictionary:json];
NSDictionary *dataDict = [containModel valueForKey:@"data"];
//定義數(shù)組,接受key為list的數(shù)組
self.listArray = [dataDict valueForKey:@"list"]; 
 //遍歷數(shù)組
[self.listArray enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        NSDictionary *listDict = obj;
        //獲取數(shù)組中得字典
        List *listModel = [List yy_modelWithDictionary:listDict];
        //獲取count 和 id
        NSString *count = [listModel valueForKey:@"count"];
        NSString *id = [listModel valueForKey:@"id"];
       

5.黑名單與白名單

@interface User
@property NSString *name;
@property NSUInteger age;
@end

@implementation Attributes
// 如果實(shí)現(xiàn)了該方法欺旧,則處理過程中會忽略該列表內(nèi)的所有屬性
+ (NSArray *)modelPropertyBlacklist {
    return @[@"test1", @"test2"];
}
// 如果實(shí)現(xiàn)了該方法姑丑,則處理過程中不會處理該列表外的屬性。
+ (NSArray *)modelPropertyWhitelist {
    return @[@"name"];
}
@end

6.數(shù)據(jù)校驗與自定義轉(zhuǎn)換

實(shí)際這個分類的目的比較簡單和明確辞友。
就是對判斷是否為時間戳,然后對時間戳進(jìn)行處理震肮,調(diào)用
_createdAt = [NSDate dateWithTimeIntervalSince1970:timestamp.floatValue];
獲取時間称龙。

// JSON:
{
    "name":"Harry",
    "timestamp" : 1445534567     //時間戳
}

// Model:
@interface User
@property NSString *name;
@property NSDate *createdAt;
@end

@implementation User
// 當(dāng) JSON 轉(zhuǎn)為 Model 完成后,該方法會被調(diào)用戳晌。
// 你可以在這里對數(shù)據(jù)進(jìn)行校驗鲫尊,如果校驗不通過,可以返回 NO沦偎,則該 Model 會被忽略疫向。
// 你也可以在這里做一些自動轉(zhuǎn)換不能完成的工作。
- (BOOL)modelCustomTransformFromDictionary:(NSDictionary *)dic {
    NSNumber *timestamp = dic[@"timestamp"];
    if (![timestamp isKindOfClass:[NSNumber class]]) return NO;
    _createdAt = [NSDate dateWithTimeIntervalSince1970:timestamp.floatValue];
    return YES;
}

// 當(dāng) Model 轉(zhuǎn)為 JSON 完成后豪嚎,該方法會被調(diào)用搔驼。
// 你可以在這里對數(shù)據(jù)進(jìn)行校驗,如果校驗不通過侈询,可以返回 NO舌涨,則該 Model 會被忽略。
// 你也可以在這里做一些自動轉(zhuǎn)換不能完成的工作扔字。
- (BOOL)modelCustomTransformToDictionary:(NSMutableDictionary *)dic {
    if (!_createdAt) return NO;
    dic[@"timestamp"] = @(n.timeIntervalSince1970);
    return YES;
}
@end
  • 需要注意的時囊嘉,如果用插件,對時間戳類型或默認(rèn)創(chuàng)建為NSUInteger類型革为,需要將其更改為NSDate類型扭粱。

7.Coding/Copying/hash/equal/description

以下方法都是YYModel的簡單封裝,實(shí)際使用過程和系統(tǒng)方法區(qū)別不大震檩。對其感興趣的可以點(diǎn)進(jìn)方法內(nèi)部查看琢蛤。

@interface YYShadow :NSObject <NSCoding, NSCopying>
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) CGSize size;
@end

@implementation YYShadow
// 直接添加以下代碼即可自動完成
- (void)encodeWithCoder:(NSCoder *)aCoder { 
 [self yy_modelEncodeWithCoder:aCoder]; 
}
- (id)initWithCoder:(NSCoder *)aDecoder {
  self = [super init];
  return [self yy_modelInitWithCoder:aDecoder]; 
}
- (id)copyWithZone:(NSZone *)zone { 
 return [self yy_modelCopy]; 
}
- (NSUInteger)hash { 
 return [self yy_modelHash]; 
}
- (BOOL)isEqual:(id)object { 
 return [self yy_modelIsEqual:object]; 
}
- (NSString *)description { 
 return [self yy_modelDescription]; 
}
@end

二、ESJsonFormat與YYModel的結(jié)合使用

彩蛋
給大家介紹一款插件恳蹲,配合ESJsonFormat

配圖:


ESJsonFormat插件使用.gif

使用方法:
快捷鍵:shift + control + J
插件安裝方法比較簡單虐块,在此不贅述,不知道可自行g(shù)oogle嘉蕾。

好處

    1. 可以直接將json數(shù)據(jù)復(fù)制贺奠,ESJsonFormat會根據(jù)數(shù)據(jù)類型自動生成屬性。(建議還是要自行檢查错忱,比如時間戳儡率,系統(tǒng)會默認(rèn)幫你生成為NSUInteger挂据,而我們想要的為NSDate類型)
    1. 對于多模型嵌套,不必創(chuàng)建多個文件儿普,ESJsonFormat會自動在一個文件下創(chuàng)建多重類型,極其便捷崎逃。

至此YYModel的使用已講解完畢,關(guān)于YYModel的底層核心是運(yùn)用runtime獲取類結(jié)構(gòu)體中Ivars眉孩,進(jìn)行KVC操作个绍,然后根據(jù)不同情況進(jìn)行分別處理
此處只是傳遞給大家一個概念浪汪,不展開講解巴柿,網(wǎng)上有很多源碼分析文章,可自學(xué)google學(xué)習(xí)死遭。
文末广恢,做個綜述。
建議大家有時間一定要多看底層呀潭,分析源碼钉迷。不要只會用,知其然不知其所以然钠署。
如有錯誤歡迎指出糠聪。

寫在最后

我得寫作原則:
在技術(shù)學(xué)習(xí)道路上,閱讀量和代碼量絕不能線性提升你的技術(shù)水平踏幻。
同樣寫文章也是如此枷颊,作者所寫的文章完全是基于自己對技術(shù)的理解,在寫作時也力求形象不抽象该面。絕不copy充數(shù)夭苗,所以也歡迎大家關(guān)注和參與討論。
技術(shù)學(xué)習(xí)絕不能孤膽英雄獨(dú)闖天涯隔缀,而應(yīng)在一群人的交流碰撞题造,享受智慧火花的狂歡。
希望我的文章能成為你的盛宴猾瘸,也渴望你的建議能成為我的大餐界赔。
如有錯誤請留言指正,對文章感興趣可以關(guān)注作者不定期更新牵触。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末淮悼,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子揽思,更是在濱河造成了極大的恐慌袜腥,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钉汗,死亡現(xiàn)場離奇詭異羹令,居然都是意外死亡鲤屡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門福侈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來酒来,“玉大人,你說我怎么就攤上這事肪凛⊙吆海” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵伟墙,是天一觀的道長衡奥。 經(jīng)常有香客問我,道長远荠,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任失息,我火速辦了婚禮譬淳,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘盹兢。我一直安慰自己邻梆,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布绎秒。 她就那樣靜靜地躺著浦妄,像睡著了一般。 火紅的嫁衣襯著肌膚如雪见芹。 梳的紋絲不亂的頭發(fā)上剂娄,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機(jī)與錄音玄呛,去河邊找鬼阅懦。 笑死,一個胖子當(dāng)著我的面吹牛徘铝,可吹牛的內(nèi)容都是我干的耳胎。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼惕它,長吁一口氣:“原來是場噩夢啊……” “哼怕午!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起淹魄,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤郁惜,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后揭北,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體扳炬,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡吏颖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了恨樟。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片半醉。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖劝术,靈堂內(nèi)的尸體忽然破棺而出缩多,到底是詐尸還是另有隱情,我是刑警寧澤养晋,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布衬吆,位于F島的核電站,受9級特大地震影響绳泉,放射性物質(zhì)發(fā)生泄漏逊抡。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一零酪、第九天 我趴在偏房一處隱蔽的房頂上張望冒嫡。 院中可真熱鬧,春花似錦四苇、人聲如沸孝凌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蟀架。三九已至,卻和暖如春榆骚,著一層夾襖步出監(jiān)牢的瞬間片拍,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工寨躁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留穆碎,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓职恳,卻偏偏與公主長得像所禀,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子放钦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理色徘,服務(wù)發(fā)現(xiàn),斷路器操禀,智...
    卡卡羅2017閱讀 134,659評論 18 139
  • 導(dǎo)語:YYModel庫是優(yōu)秀的模型轉(zhuǎn)換庫褂策,可自動處理模型轉(zhuǎn)換(從JSON到Model 和 Model到JSON)的...
    南華coder閱讀 5,455評論 0 11
  • 概述 ? iOS源碼解析—YYModel(YYClassInfo)分析了如何根據(jù)OC的Class對象構(gòu)建...
    egoCogito_panf閱讀 11,582評論 4 32
  • 對我來說最重要的事就是自己能想到的,然后逐步的去把每件事情做好,這是就是最重要的事情斤寂。至于是正確的事還是正確的做事...
    小李非刀閱讀 1,331評論 0 4
  • 冥想沒有那么神秘 這個詞這么神秘耿焊,其實(shí)冥想只是讓內(nèi)心跳來跳去的猴子安靜下來,什么都不需要做遍搞,就是關(guān)注呼吸罗侯,安住當(dāng)下...
    黑土錢閱讀 172評論 2 0