runtime實(shí)戰(zhàn):JSON轉(zhuǎn)實(shí)體-HBEntity

我們應(yīng)該經(jīng)常能碰到這樣的場(chǎng)景:在網(wǎng)絡(luò)數(shù)據(jù)回來之后需要將網(wǎng)絡(luò)數(shù)據(jù)轉(zhuǎn)化成實(shí)體(model),通常的做法是利用kvc來為實(shí)體賦值,或者利用現(xiàn)在已有的MJExtention、YYModel來做。

今天以我自己寫的HBEntity為例解析下如何利用runtime來為實(shí)體賦值。


HBEntity簡介:

HBEntity是一個(gè)利用runtime來將NSArray或NSDictionary對(duì)象轉(zhuǎn)化成自定義實(shí)體的工具,支持多實(shí)體嵌套、免除了MJExtention和YYModel中白名單和黑名單的概念,同時(shí)還支持key與屬性名之間的適配。

實(shí)現(xiàn)思路:

HBEntity實(shí)現(xiàn)將NSArray或NSDictionary對(duì)象轉(zhuǎn)化成自定義實(shí)體的思路比較簡單。我們把問題轉(zhuǎn)換一下,上學(xué)的時(shí)候我們經(jīng)常會(huì)遇到解y=f(x)的問題,現(xiàn)在把x與我們的NSArray和NSDictionary對(duì)象對(duì)應(yīng),y與我們自定義實(shí)體對(duì)應(yīng),f函數(shù)就是我們的HBEntity,我們來捋一下我們的已知條件,我們已知x和y,要求f! WTF,怎么解 。。 從x、y去推f,這個(gè)f可能有很多種?。?!我比較喜歡倒推。既然我們是要給自定義實(shí)體賦值,那我們需要知道這個(gè)實(shí)體有多少屬性,每個(gè)屬性是什么類型,有沒有自定義getter 和setter方法等。runtime在這個(gè)時(shí)候就派上用場(chǎng)了。

在拿到實(shí)體所有的屬性之后剩下的就是用NSDictionary或者NSArray對(duì)象(為了方便以下都簡稱為“對(duì)象”,我們自定義的類稱為實(shí)體)賦值了。所以在這里我也不需要去過濾對(duì)象中哪些值是我不想?yún)⑴c賦值的(也就是blacklist),對(duì)于我來說沒有blacklist和whitelist的區(qū)分。

總結(jié)起來為:

1.解析實(shí)體的屬性

2.用對(duì)象的值為實(shí)體的屬性賦值。

下面我們邊看代碼吧邊bb吧。

1.解析實(shí)體的屬性——runtime

解析實(shí)體的屬性時(shí)我們會(huì)用到 class_copyPropertyList方法,

OBJC_EXPORT objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)

__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);

該方法會(huì)將cls類里所有的屬性都放到一個(gè)數(shù)組里返回,outCount返回的是屬性的數(shù)量,如果該cls有父類,class_copyPropertyList方法并不會(huì)返回父類的屬性,當(dāng)然也不會(huì)將父類屬性的個(gè)數(shù)計(jì)算到outCount內(nèi)。這里需要說明的是objc_property_t是一個(gè)objc_property的結(jié)構(gòu)體指針,objc_property有name 和 attributes,如果我們聲明了一個(gè)屬性

@property (nonatomic,copy,readonly)NSString *test;

這里test就是objc_property的name,可以通過property_getName來獲取,而attributes可以通過property_getAttributes來獲取,attributes是我們聲明的屬性(nonatomic,copy,readonly等)的描述,我們先來看下一個(gè)測(cè)試Demo返回的attribues,再來蘋果文檔里是怎么描述這一塊的。

T@“NSString”,C,N,V_entityName這一串就是attributes

從上圖可以看出,每個(gè)attribute都有name和value兩部分組成,我們可以通過property_copyAttributeList來獲得某個(gè)屬性的atrributeList,每一項(xiàng)是objc_property_attribure_t類型,objc_property_attribure_t類型如下:

/// Defines a property attribute

typedef struct {

const char *name;? ? ? ? ? /**< The name of the attribute */

const char *value;? ? ? ? ? /**< The value of the attribute (usually empty) */

} objc_property_attribute_t;

那具體T、C、N這些符號(hào)代表的是什么意思呢?他的值又表示的是什么呢?我們求助一下官方文檔。

上面是官方文檔對(duì)T、C、N等做出的解答。下面再來看看他們的值代表的什么意思。

這里是官方文檔的部分截圖,可以看出我們可以通過T來知道該屬性的類型。

官方文檔里展示的例子并沒有包含所有的類型,在我的HBEntity里有補(bǔ)充(下載地址:https://github.com/knighthb/HBEntity),感興趣的同學(xué)可以下載下來看看。

基本上通過以上的幾個(gè)方法就能確定一個(gè)類里有多少屬性(不含父類的屬性)、每個(gè)屬性是詳細(xì)信息等。

2.利用對(duì)象為實(shí)體賦值

這里基本上就是鍵值對(duì)映射,如果在適配器里為key和屬性名做了適配,那么在賦值時(shí)將會(huì)把key對(duì)應(yīng)的value賦值給對(duì)應(yīng)的屬性。

對(duì)于普通的類(屬性里沒有自定義類、沒有數(shù)組等的類)這些工作已經(jīng)足夠了,對(duì)于比較棘手的我們就需要進(jìn)行一下處理,比如對(duì)于屬性是NSArray或NSMutableArray的類賦值時(shí)我們需要知道NSArray里裝的是什么,也許有同學(xué)會(huì)說,這個(gè)簡單,我們聲明屬性的時(shí)候聲明為NSArray這樣的形式就知道它是NSString的啦,乍一看是的,但是你用runtime根本拿不出來,因?yàn)檫@種寫法是編譯時(shí)的,只是告訴編譯器array里裝的是NSString,所以在runtime根本找不到。因此這塊避免不了MJExtention或YYModel里指定類名的這類操作,如果有同學(xué)有好的解決方法請(qǐng)不吝賜教。

另外還有一個(gè)棘手的問題就是數(shù)值類型的處理,需要裝箱拆箱過程,一直沒有想出出去硬編碼的方法,如果有同學(xué)解決過類似的問題也請(qǐng)不吝賜教。

最后上點(diǎn)Demo:

//HBTestPerson.h

#import "HBEntity.h"

#import "HBTestEntity.h"

@interface HBTestPerson : HBEntity

@property (nonatomic , copy)NSString * entityName;

@property (nonatomic , strong) NSString *entityNum;

@property (nonatomic , strong,setter=setEntityAge2:) HBTestEntity *testEntity;

@property (nonatomic , strong) NSMutableArray* testEntities;

@property (nonatomic , assign) BOOL boolTest;

@end

//HBTestPerson.m

#import "HBTestPerson.h"

@implementation HBTestPerson

- (NSDictionary *)hb_transferDic {

return @{@"entityname":@"entityName",

@"entitynum":@"entityNum"};

}

+ (NSDictionary *)hb_objectClassForKeyDic {

return @{@"testEntities":[HBTestEntity class]};

}

- (void)setEntityAge2:(HBTestEntity *)entityAge {

_testEntity = entityAge;

}

@end

//HBTestEntity.h

#import "HBEntity.h"

@interface HBTestEntity : HBEntity

@property (nonatomic , copy) NSString * name;

@property (nonatomic , copy) NSNumber * age;

@end

//HBTestEntity.m

#import "HBTestEntity.h"

@implementation HBTestEntity

- (void)setName:(NSString *)name {

_name = name;

}

@end

//HBArrayTestEntity.h

#import "HBEntity.h"

@interface HBArrayTestEntity : HBEntity

@property (nonatomic , strong) NSMutableArray * array;

@end

//HBArrayTestEntity.m

#import "HBArrayTestEntity.h"

#import "HBTestEntity.h"

@implementation HBArrayTestEntity

+ (NSDictionary *)hb_objectClassForKeyDic {

return @{@"array":[HBTestEntity class]};

}

@end

上面是幾個(gè)測(cè)試類,下面是測(cè)試代碼

NSDictionary * entityDic = @{@"entityname":@"hehe",

@"entitynum":@"1",

@"testEntity":@{@"name":@"xiaoming",

@"age":@(34)

},

@"testEntities":@[@{@"name":@"xiaoming",

@"age":@(34)

},

@{@"name":@"xiaoming",

@"age":@(34)

},

@{@"name":@"xiaoming",

@"age":@(34)

}]};

HBTestPerson * entity = [HBTestPerson transferEntityWithDic:entityDic];

NSArray * entityArray = @[@{@"name":@"xiaoming",

@"age":@(34)

},

@{@"name":@"xiaoming",

@"age":@(34)

},

@{@"name":@"xiaoming",

@"age":@(34)

}];

HBArrayTestEntity * arrayTestEntity = [HBArrayTestEntity transferEntityWithObject:entityArray];

結(jié)果如下:


總結(jié):

不要臉的取了個(gè)總結(jié),主要是為了貼下github的地址

github地址:https://github.com/knighthb/HBEntity

或者 git clone https://github.com/knighthb/HBEntity.git

也可以通過Pod 來安裝 HBEntity玩耍

pod 'HBEntity'

希望通過解析HBEntity能讓大家對(duì)runtime能有不一樣的認(rèn)識(shí),如果大家在玩耍的過程中遇到了問題或者發(fā)現(xiàn)了bug請(qǐng)及時(shí)聯(lián)系我

QQ:513179531

微信:knight_hb

或者在底下留言 ^ ^

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 兩天早上拿著筆沒流出什么東西。 今天下班前開了個(gè)小會(huì),把這兩天做的東西總結(jié)了一番,接下來幾天是項(xiàng)目比較具有挑戰(zhàn)性的...
    大瑞RayD閱讀 566評(píng)論 1 3
  • 今天是平安夜,一個(gè)充滿寓意與無限美好的日子。 走到校園外,天空剛好下起了微微雨,武漢的冬天就是這樣,存在于微風(fēng)、寒...
    聞香識(shí)妞閱讀 542評(píng)論 7 6
  • —————1.初始化( key一定要是可以hash的(String, Int, Float, Double, Bo...
    Jason_Wong閱讀 6,915評(píng)論 0 4
  • 你想知道我對(duì)你的愛情是什么嗎?就是從心底里喜歡你,覺得你的一舉一動(dòng)都很親切,不高興你比喜歡我更喜歡別人。你要是喜歡...
    一念歸遠(yuǎn)閱讀 75評(píng)論 0 0

友情鏈接更多精彩內(nèi)容