JSON轉Model內部實現解析,json轉model解析

來源:互聯網
上載者:User

JSON轉Model內部實現解析,json轉model解析

一、思路:1、通過模型類型獲得所有的屬性和其類型2、對獲得的json進行處理。類型處理3、考慮字典索引值和模型屬性名稱不一致的情況4、添加code用于歸檔5、補充JSON轉字典、字典轉JSON、字典轉模型等介面6、對處理過的properties做緩衝 二、設計模式思考:設計模式的選擇---------繼承、介面、抽象基類的選擇。在使用方便、高效率、低耦合之間抉擇。 三、細節及實現先把任務分解,實現各個部分細節,然後進行組合,當然我們要思考好,採用何種設計模式組裝。先來看看各個部分的實現細節。 1.通過模型類型獲得所有的屬性和其類型,   
 unsigned int outCount = 0;     //獲得Class c所有屬性這裡的c是[Model class]    objc_property_t *properties = class_copyPropertyList(c, &outCount);        for (int i = 0; i < outCount; i++) {        objc_property_t propert = properties[i];       //獲得屬性名稱        NSString *key = @(property_getName(propert));        //獲得屬性類型,如CGFloat、nonatomic、copy等資訊        NSString *type = @(property_getAttributes(propert));        NSLog(@"key = %@ , type = %@", key, type);     }

 Model模型如下

//屬性}typedef void(^block)();@interface Model : NSObject@property (nonatomic, copy) NSString *q_NSString;@property (nonatomic, assign) CGFloat q_CGFloat;@property (nonatomic, assign) CGRect q_CGRect;@property (nonatomic, assign) double q_double;@property (nonatomic, assign) int q_int;@property (nonatomic, assign) BOOL q_bool;@property (nonatomic, assign) float q_float;@property (nonatomic, assign) short q_short;@property (nonatomic, assign) long q_long;@property (nonatomic, assign) long long q_longlong;@property (nonatomic, assign) Point q_point;@property (nonatomic, strong) id q_id;@property (nonatomic, weak) id<NSObject> q_delegate;@property (nonatomic, copy) block q_block;@property (nonatomic, strong) Model1 *q_model1; @property SEL q_SEL;@property Class q_Class;@property Ivar q_Ivar;@property Method q_Method;

輸出結果為

key = q_NSString , type = T@"NSString",C,N,V_q_NSStringkey = q_CGFloat , type = Td,N,V_q_CGFloatkey = q_CGRect , type = T{CGRect={CGPoint=dd}{CGSize=dd}},N,V_q_CGRectkey = q_double , type = Td,N,V_q_doublekey = q_int , type = Ti,N,V_q_intkey = q_bool , type = TB,N,V_q_boolkey = q_float , type = Tf,N,V_q_floatkey = q_short , type = Ts,N,V_q_shortkey = q_long , type = Tq,N,V_q_longkey = q_longlong , type = Tq,N,V_q_longlongkey = q_point , type = T{Point=ss},N,V_q_pointkey = q_id , type = T@,&,N,V_q_idkey = q_delegate , type = T@"<NSObject>",W,N,V_q_delegatekey = q_block , type = T@?,C,N,V_q_blockkey = q_model1 , type = T@"Model1",&,N,V_q_model1key = q_SEL , type = T:,V_q_SELkey = q_Class , type = T#,&,V_q_Classkey = q_Ivar , type = T^{objc_ivar=},V_q_Ivarkey = q_Method , type = T^{objc_method=},V_q_Method

 

將type用”,”分開,以T@"NSNumber",N,R,Vname  為例在類中的聲明為 let name: NSNumber =  NSNumber()
  • T@“NSNumber” 標記了屬於什麼類型
  • N            安全執行緒 相當與Objective-C中的nonmatic
  • R            不可變,R相當與Objective-C中的readonly,C相當於copy        
  • Vname        去掉V,name就是變數名
通過對type進行處理就可以獲得屬性的類型。從而進行下一步處理。注意點:class_copyPropertyList返回的僅僅是對象類的屬性,class_copyIvarList返回類的所有屬性和變數,在swift中如let a: Int? 是無法通過class_copyPropertyList返回的。 2.對type的處理使用方法可能不同,但是目的是一樣的,就是為了從type字串中區分出不同的類型主要分為這幾種:對象、協議、block、基本類型、結構體、自訂類型、Class、Ivar、Method、SEL、 MJExtension採用這樣區分,在MJExtensionConst中這樣定義
NSString *const MJPropertyTypeInt = @"i";NSString *const MJPropertyTypeShort = @"s";NSString *const MJPropertyTypeFloat = @"f";NSString *const MJPropertyTypeDouble = @"d";NSString *const MJPropertyTypeLong = @"l";NSString *const MJPropertyTypeLongLong = @"q";NSString *const MJPropertyTypeChar = @"c";NSString *const MJPropertyTypeBOOL1 = @"c";NSString *const MJPropertyTypeBOOL2 = @"b";NSString *const MJPropertyTypePointer = @"*";NSString *const MJPropertyTypeIvar = @"^{objc_ivar=}";NSString *const MJPropertyTypeMethod = @"^{objc_method=}";NSString *const MJPropertyTypeBlock = @"@?";NSString *const MJPropertyTypeClass = @"#";NSString *const MJPropertyTypeSEL = @":";NSString *const MJPropertyTypeId = @"@";
MJExtension採用對type進行字串處理就能夠區分出具體的類型而在JSONModel採用 NSScanner,對類型進行處理。比較下,個人覺得採用定義MJExtensionConst這樣一個類來存放區分的值顯得更加清晰。對於閱讀原始碼的人來說相對比較好。當然也可以結合起來使用 3.對獲得的JSON進行類型處理。

  • 在JSON中為NSNumer,而propertytype為NSString,這種情況很常見。我們就需要處理一下,當propertytype為NSString,而在JSON中為NSNumber,就把NSNumber轉化為NSString。
  • Readonly不需要賦值
  • nil處理
  • 可變和不可變處理
  • 模型就需要遞迴處理
  • NSString -> NSURL
  • 字串轉BOOL
  • 還有一些其他處理,以上的處理中也不是每個第三方都進行處理了
截取MJEextension中的一部分代碼        
  if ([value isKindOfClass:[NSStringclass]]) {                    if (propertyClass == [NSURL class]) {                        // NSString -> NSURL                        // 字串轉碼                        value = [value mj_url];                    } else if (type.isNumberType) {                        NSString *oldValue = value;                                               // NSString -> NSNumber                        value = [numberFormatter_ numberFromString:oldValue];                                               // 如果是BOOL                        if (type.isBoolType) {                            // 字串轉BOOL(字串沒有charValue方法)                            // 系統會調用字串的charValue轉為BOOL類型                            NSString *lower = [oldValue lowercaseString];                            if ([lower isEqualToString:@"yes"] || [lower isEqualToString:@"true"]) {                                value = @YES;                            } else if ([lower isEqualToString:@"no"] || [lower isEqualToString:@"false"]) {                                value = @NO;                            }                        }                    }                }

 

4.採用KVC賦值setValue:forKey: 就不多說了 5.考慮字典索引值和模型屬性名稱不一致的情況比如id、descripition不能作為屬性名稱,當伺服器使用時我們就需要另外構造名字;還有伺服器一般使用user_name的命名方式,而OC中一般使用駝峰命名法即userName,那麼我們就需要建立一對一的對應關係。 我想到有三種方法處理:
  •      採用繼承,定義model基類,子類重寫父類方法。
  •      block設定block回調。
  •      可以採用抽象基類。
      這個部分就需要我們好好考慮下了,因為涉及到我們如何提供介面,使用者如何使用的問題。需要考慮到使用是否方便、效率高低、低耦合是否高等問題。     先來說第一種,採用繼承的方法,無疑的會帶來高耦合的後果,當然在設計合理的情況下,大部分情況下使用起來更方便。     第二種採用block的方法。解決了繼承帶來的高耦合的成本。使用起來也很方便。MJEextension就是用這種方法。但是這種方法往往讓我們在調用轉化方法時調用block,些一大串的不同索引值的轉化。個人覺得不同索引值的轉化寫在model裡面比較好,而且在封裝時,就有意識地引導使用者這麼做  第三種方法使用抽象基類,定義一個協議,協議提供一個或者幾個索引值轉化的方法。當model遵守並實現了此協議,就找到處理方法進行處理。這種作法避免了繼承的高耦合的成本,也是使用者在model遵守協議,實現此方法。索引值轉化的方法寫在model裡面,避免轉化的地方些太多東西。有時候還要寫幾遍。當然這樣也有些缺點,就是每次有需要轉化時(而且索引值不同的情況很常見)需要引入,然後遵守協議。連續建幾個model時,複製起來都不方便。 6.其他方面    (未測試) 對於SEL、Method 、Ivar不能使用KVC,如果考慮這些情況,需要進行判斷。    在賦值時,設定可以忽略的屬性 7.添加code用于歸檔  添加方法
- (id)initWithCoder:(NSCoder *)decoder- (void)encodeWithCoder:(NSCoder *)encoder
 一般是給NSObject添加分類,因為我們可以得到類的所有屬性和對應的值。在兩個方法中遍曆屬性,進行編碼和解碼。方便做些緩衝,很多的頁面緩衝就可以這樣做。使用比較方便。 8.補充JSON轉字典
+ (NSDictionary *)dictionaryWithJsonString:(NSString *)jsonString {  if (jsonString == nil) {    return nil;  }  NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];  NSError *error;  NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData                                                             options:NSJSONReadingMutableContainers                                                       error:&error];  if(error) {    NSLog(@"json解析失敗:%@",error);    return nil;  }  return dic;}
 此方法稍作變換,也可輸出數組,主要看json格式。 9.字典轉JSON
+ (NSString*)dictionaryToJson:(NSDictionary *)dic{    NSError *error = nil;    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dic 
                                 options:NSJSONWritingPrettyPrinted
                                 error:&error]; return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];}

 

10.對處理過的properties一般需要做緩衝     定義一個字典緩衝,緩衝處理過的properties,重複使用是不需要重複計算,用空間換時間。例如在歸檔的時候需要獲得屬性名稱列表,然後遍曆歸檔、解擋。其他中間操作也需要用到properties。 水平有限,錯誤之處,歡迎大家指正。互相學習。轉載請註明出處

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.