自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

iOS手動(dòng)打造JSON Model轉(zhuǎn)換庫

移動(dòng)開發(fā) iOS
前一段時(shí)間學(xué)習(xí)了Runtime,對類和對象的結(jié)構(gòu),和一些消息轉(zhuǎn)發(fā)有一些自己的理解,現(xiàn)在希望簡單的應(yīng)用下,就決定自己寫一個(gè)簡單的JSON與Model的相互轉(zhuǎn)化,現(xiàn)在總結(jié)下。

 觀察下面這個(gè)JSON數(shù)據(jù)和Model數(shù)據(jù)

  1. NSString *girlFriend = @"白菜";  
  2. id parmenters = @{  
  3.         @"girlFriend":girlFriend,  
  4.         @"age":@22.1,  
  5.         @"name":@"Lastdays",  
  6.         @"time":@"2016-03-18 5:55:49 +0000"  
  7. }; 
  1. @interfaceModel: NSObject  
  2.    
  3. @property NSNumber *age;  
  4. @property NSString *name;  
  5. @property NSString *girlFriend;  
  6. @property NSData *time;  
  7.    
  8. @end 

開始的時(shí)候仔細(xì)想了一下,如何能夠動(dòng)態(tài)的去添加屬性值,并且根據(jù)對應(yīng)的屬性進(jìn)行賦值,還要保證類型正確,這是我最開始考慮的問題。但是最核心問題就是 動(dòng)態(tài)實(shí)現(xiàn) 。

我們一步一步來解決問題,首先我們先獲取Model屬性,取得Model的一些信息
獲取Model屬性

runtime提供了 class_copyPropertyList 來獲取屬性列表,OK,我們可以來看一下用它獲取的數(shù)據(jù)是什么樣的?查看runtime源碼

  1. /***********************************************************************  
  2. * class_copyPropertyList. Returns a heap block containing the  
  3. * properties declared in the class, or nil if the class  
  4. * declares no properties. Caller must free the block.  
  5. * Does not copy any superclass's properties.  
  6. **********************************************************************/  
  7. objc_property_t*class_copyPropertyList(Class cls, unsigned int *outCount)  
  8. {  
  9.     old_property_list*plist;  
  10.     uintptr_titerator = 0;  
  11.     old_property**result = nil;  
  12.     unsigned int count = 0;  
  13.     unsigned int p, i;  
  14.    
  15.     if (!cls) {  
  16.         if (outCount) *outCount = 0;  
  17.         return nil;  
  18.     }  
  19.    
  20.     mutex_locker_tlock(classLock);  
  21.    
  22.     iterator = 0;  
  23.     while ((plist = nextPropertyList(cls, &iterator))) {  
  24.         count += plist->count;  
  25.     }  
  26.    
  27.     if (count > 0) {  
  28.         result = (old_property**)malloc((count+1) * sizeof(old_property*));  
  29.    
  30.         p = 0;  
  31.         iterator = 0;  
  32.         while ((plist = nextPropertyList(cls, &iterator))) {  
  33.             for (i = 0; i < plist->count; i++) {  
  34.                 result[p++] = property_list_nth(plist, i);  
  35.             }  
  36.         }  
  37.         result[p] = nil;  
  38.     }  
  39.    
  40.     if (outCount) *outCount = count;  
  41.     return (objc_property_t*)result;  
  1. typedef struct old_property*objc_property_t; 
  1. struct old_property {  
  2.     const char *name;  
  3.     const char *attributes;  
  4. }; 

從上面的三段runtime源碼中,課本上就能判斷出,其實(shí)返回結(jié)果就是一些old_property,并且每個(gè)old_property中含有對應(yīng)的name和其他信息。

總結(jié)起來說就是**class_copyPropertyList**獲取Model屬性列表,屬性列表里面的objc_property_t包含著這個(gè)屬性的類型和名字等一些信息。

根據(jù)剛才的分析設(shè)計(jì)出以下結(jié)構(gòu):

  1. bash  
  2. -(id)modelToJsonObject:(NSObject *)model{  
  3.    
  4.     Class cls = self.class;  
  5.     unsigned int countProperty = 0;  
  6.     objc_property_t*propertys = class_copyPropertyList(cls,&countProperty);  
  7.     NSMutableDictionary *dic = [NSMutableDictionary new];  
  8.    
  9.     for (unsigned int i = 0; i<countProperty; i++) {  
  10.         PropertyInfo *propertyInfo = [[PropertyInfo alloc]initWithProperty:propertys[i]];  
  11.         if (propertyInfo.propertyName!=nil) {  
  12.             dic[propertyInfo.propertyName] = [selfLYModelSetJsonObjectWith:modelpropertyInfo:propertyInfo];  
  13.         }  
  14.     }  
  15.     return dic;  

PropertyInfo也就是屬性信息,我們將Model的所有屬性存放到 NSMutableDictionary 中,key就是屬性名,Value就是PropertyInfo。

接下來開始獲取Model的屬性信息 PropertyInfo

我們可以通過property_getName來獲取屬性名

  1. const char *property_getName(objc_property_tprop)  
  2. {  
  3.     return oldproperty(prop)->name;  

接下來就是獲取屬性的類型和一些其他的信息。獲取屬性的信息其實(shí)和上面的原理差不多,我們使用property_copyAttributeList,

  1. objc_property_attribute_t*property_copyAttributeList(objc_property_tprop,   
  2.                                                       unsigned int *outCount)  
  3. {  
  4.     if (!prop) {  
  5.         if (outCount) *outCount = 0;  
  6.         return nil;  
  7.     }  
  8.    
  9.     mutex_locker_tlock(classLock);  
  10.     return copyPropertyAttributeList(oldproperty(prop)->attributes,outCount);  

看到這里,不往下繼續(xù)分析源碼了,其實(shí)可以看到,attributes就是我們想要的信息,其實(shí)每個(gè)property也是有自己對應(yīng)的attributes。

這個(gè)attributes是什么樣呢?翻看源碼,找到了答案

  1. typedef struct {  
  2.     const char *name;        
  3.     const char *value;          
  4. } objc_property_attribute_t; 

加一下斷點(diǎn),看看

可以看到,name是T,Value是NSNumber,我們來獲取下NSNumber這個(gè)屬性類型。

  1. for (unsigned int i = 0; i<attrCount; i++) {  
  2.     if (attrs[i].name[0] == 'T') {  
  3.         size_tlen = strlen(attrs[i].value);  
  4.         if (len>3) {  
  5.             char name[len - 2];  
  6.             name[len - 3] = '';  
  7.             memcpy(name, attrs[i].value + 2, len - 3);  
  8.             _typeClass = objc_getClass(name);  
  9.         }  
  10.     }  

基本上我們想要的信息基本上都已經(jīng)獲取到了,現(xiàn)在接下來就是做動(dòng)態(tài)設(shè)定。

中間做個(gè)插曲簡單的說下Objc是動(dòng)態(tài)語言,[receiver message]的執(zhí)行過程當(dāng)中,[receiver message]是會被動(dòng)態(tài)編譯的,Objc是動(dòng)態(tài)語言,因此它會想盡辦法將編譯連接推遲到運(yùn)行時(shí)來做。runtime這個(gè)時(shí)實(shí)運(yùn)行系統(tǒng)就是來執(zhí)行編譯后的代碼。

在這個(gè)消息發(fā)送過程中,objc_msgSend充當(dāng)著很重要的角色,所以我們可以主動(dòng)觸發(fā)objc_msgSend,來模擬getter,setter方法獲取屬性值,或者建立。

我們通過SEL來定義選擇器,選擇器是什么?就是方法名的唯一標(biāo)識符

根據(jù)剛才的想法,編寫的代碼***是這個(gè)樣子

  1. -(instancetype)initWithProperty:(objc_property_t)property{  
  2.     _property = property;  
  3.    
  4.     const char *name = property_getName(property);  
  5.     if (name) {  
  6.         _propertyName = [NSStringstringWithUTF8String:name];  
  7.     }  
  8.     unsigned int attrCount;  
  9.     objc_property_attribute_t*attrs = property_copyAttributeList(property, &attrCount);  
  10.     for (unsigned int i = 0; i<attrCount; i++) {  
  11.         if (attrs[i].name[0] == 'T') {  
  12.             size_tlen = strlen(attrs[i].value);  
  13.             if (len>3) {  
  14.                 char name[len - 2];  
  15.                 name[len - 3] = '';  
  16.                 memcpy(name, attrs[i].value + 2, len - 3);  
  17.                 _typeClass = objc_getClass(name);  
  18.             }  
  19.         }  
  20.     }  
  21.     NSString *setter = [NSStringstringWithFormat:@"set%@%@:", [_propertyNamesubstringToIndex:1].uppercaseString, [_propertyNamesubstringFromIndex:1]];  
  22.     _setter =  NSSelectorFromString(setter);  
  23.     _getter = NSSelectorFromString(_propertyName);  
  24.    
  25.     return self;  

基本的準(zhǔn)備工作,和一些問題都解決了,接下來可以寫功能了。
JSON轉(zhuǎn)Model

根據(jù)剛才說的,我們可以主動(dòng)觸發(fā)objc_msgSend,來模擬setter方法建立屬性值。設(shè)計(jì)出以下方法

  1. -(void)LYModelSetPropertyWithModel:(id) modelvalue:(id)valuepropertyInfo:(PropertyInfo *) propertyInfo{  
  2.     ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, propertyInfo.setter, value);  

我們將Model的所有屬性存放到 NSMutableDictionary 中,key就是屬性名,Value就是PropertyInfo。

現(xiàn)在就可以動(dòng)態(tài)設(shè)定了

  1. -(BOOL)LYModelSelectProperties:(NSDictionary *)dictonary{  
  2.    
  3.     ClassInfo *cls = [[ClassInfo alloc]initWithClass:object_getClass(self)];  
  4.     id key, value;  
  5.     NSArray *keys = [dictonaryallKeys];  
  6.     NSUInteger count = [keyscount];  
  7.     for (int i = 0; i < count; i++){  
  8.         key = [keysobjectAtIndex: i];  
  9.         value = [dictonaryobjectForKey: key];  
  10.    
  11.         if (cls.propertyInfo[key]) {  
  12.             [selfLYModelSetPropertyWithModel:selfvalue:valuepropertyInfo:cls.propertyInfo[key]];  
  13.         }  
  14.     }  
  15.     return YES;  

完成動(dòng)態(tài)設(shè)定
Model轉(zhuǎn)JSON

原理跟JSON轉(zhuǎn)Model

我們可以主動(dòng)觸發(fā)objc_msgSend,來模擬getter方法來獲取屬性值。

  1. -(id)LYModelSetJsonObjectWith:(id)modelpropertyInfo:(PropertyInfo *)propertyInfo{  
  2.     id value = ((id (*)(id, SEL))(void *) objc_msgSend)((id)model, propertyInfo.getter);  
  3.     return value;  

建立NSDictionary

  1. -(id)modelToJsonObject:(NSObject *)model{  
  2.    
  3.     Class cls = self.class;  
  4.     unsigned int countProperty = 0;  
  5.     objc_property_t*propertys = class_copyPropertyList(cls,&countProperty);  
  6.     NSMutableDictionary *dic = [NSMutableDictionary new];  
  7.    
  8.     for (unsigned int i = 0; i<countProperty; i++) {  
  9.         PropertyInfo *propertyInfo = [[PropertyInfo alloc]initWithProperty:propertys[i]];  
  10.         if (propertyInfo.propertyName!=nil) {  
  11.             dic[propertyInfo.propertyName] = [selfLYModelSetJsonWith:modelpropertyInfo:propertyInfo];  
  12.         }  
  13.     }  
  14.     return dic;  

完成獲取
測試

  1. NSString *girlFriend = @"白菜";  
  2.     id parmenters = @{  
  3.                       @"girlFriend":girlFriend,  
  4.                       @"age":@22.1,  
  5.                       @"name":@"Lastdays",  
  6.                       @"time":@"2016-03-18 5:55:49 +0000"  
  7.                       };  
  8.    
  9.     Model *model = [ModelLYModelWithJSON:parmenters];  
  10.     NSLog(@"%@",model.girlFriend);  
  11.     NSLog(@"%@",model.name);  
  12.     NSLog(@"%@",model.age);  
  13.     NSLog(@"%@",model.time);  
  14.    
  15.     NSLog(@"========================================");  
  16.    
  17.     NSDictionary *jsonObject= [modelLYModelToJson];  
  18.     NSLog(@"%@",jsonObject); 

結(jié)果:

總結(jié)

簡單的JSON Model轉(zhuǎn)換庫,關(guān)鍵點(diǎn)就是在于對runtime的理解。就當(dāng)自己的一個(gè)小練習(xí),后續(xù)會繼續(xù)維護(hù),讓它對更多類型進(jìn)行支持。代碼結(jié)構(gòu)上可能不是那么好,后續(xù)會將整體的結(jié)構(gòu)重新設(shè)計(jì)下,增加可讀性,也歡迎來提出建議。

責(zé)任編輯:陳琳 來源: 伯樂在線
相關(guān)推薦

2016-11-29 10:20:50

SwiftJSONModel工具庫

2015-10-28 09:55:39

Swift解析生產(chǎn)庫

2011-04-22 13:44:34

JacksonJSON

2014-07-17 10:06:02

Model-View-iOS App

2010-06-30 11:16:50

SQL Server

2009-06-15 15:10:02

Java數(shù)據(jù)轉(zhuǎn)換JSON

2015-08-07 09:33:24

RuntimeModel

2022-10-13 21:07:48

數(shù)據(jù)庫SQL Server

2015-11-24 09:53:22

AngularJSXMLJSON

2010-01-05 14:49:03

JSON格式

2009-08-13 09:33:07

JavaBean到XM

2020-10-22 08:01:52

XMLJSON轉(zhuǎn)換

2010-01-08 10:49:21

JSON 轉(zhuǎn)換工具

2020-06-10 14:16:57

iOS 13.6 be蘋果更新

2024-03-12 09:10:21

GoarenaAPI

2010-01-08 10:24:38

轉(zhuǎn)換JSON

2021-08-20 16:37:42

SparkSpark Strea

2024-05-16 08:28:20

類型處理器D3BootJSON

2012-12-24 14:53:44

ios

2021-01-04 05:40:58

MySQL數(shù)據(jù)庫
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號