Json轉Model
json轉model,是個開發都會遇到過。都已經9102年了,誰還不會用個第三方框架搞。拿起鍵盤就是幹!
開啟podfile,把大名頂頂的YYModel寫上,pod install一下。再用上ESJsonFormat,直接根據json,都能把model生成好。特殊處理
啥?返回的欄位值不是我們所需的 在日常開發中,經常會遇到一些介面欄位返回的值,並不是我所需要的型別的情況,這個時候,我們都會對這個欄位進行處理。 舉個栗子:
/** 錯誤程式碼 */
@property (nonatomic, assign) NSInteger error_code;
/** 錯誤訊息 */
@property (nonatomic, copy) NSString *error_msg;
/** 是否成功 */
@property (nonatomic, assign) BOOL isSuccess;
複製程式碼
介面的json中的error_code欄位,介面會用這個欄位告訴我這次請求是否成功。比方說成功的error_code是1,平時我們為了方便開發,會在model裡自己加一個自定義的屬性isSuccess,來表示本次網路請求回來之後的結果是否成功。通常的做法,要麼重寫error_code的set方法,在set的時候,做一次error_code==1的判斷,將判斷的結果,賦值給isSuccess,要麼就重寫isSuccess的get方法,get的時候,返回error_code==1的結果。 相信這些對於老司機們而言,都屬於常規操作了。那我們來看看坑在什麼地方?
入坑
我們來看這個案例: 介面返回了4個欄位值,每個欄位都用得到,所以新建一個model類來解析。
@interface ExamSubjectVo : NSObject
/** 考試學科ID */
@property (nonatomic, assign) NSInteger examSubjectValue;
/** 考試學科名稱 */
@property (nonatomic, strong) NSString *examSubjectName;
/** 學科分數 */
@property (nonatomic, strong) NSString *subjectScore;
/** 基礎學科Id */
@property (nonatomic, assign) NSInteger subjectBaseId;
@end
複製程式碼
但是由於有業務需求,且為了方便開發過程區分,需要對考試名稱的欄位examSubjectName為全科或者語數外的情況,要特殊處理。所以,按照一貫的思維,我們要重寫set方法
- (void)setExamSubjectName:(NSString *)examSubjectName{
_examSubjectName = examSubjectName;
if ([examSubjectName isEqualToString:@"全科"]) {
self.subjectBaseId = -100;
}
if ([examSubjectName isEqualToString:@"語數外"]) {
self.subjectBaseId = -200;
}
}
複製程式碼
乍一看,也沒什麼問題,解析的過程中,把欄位的值轉化為我們需要的。而且真機實測的時候,所有的測試機都沒問題,除了一臺iPhone5之外 就除了一臺iPhone5,debug的時候看到set方法確實也走了,可是最終的subjectBaseId並沒有轉化成-100或者-200,可見subjectBaseId又被json本身的值覆蓋了,也就是說 set方法的執行順序,在不同CPU架構裝置上存在差異。
出坑
那麼如何解決問題呢? 正是因為存在這樣的差異,所以我們只能在model所有的欄位全部set完畢之後,再做一些特殊的欄位處理,那麼如何來處理呢? 翻閱YYModel原始碼,肯定能有所發現,果不其然,有所收穫。
/**
If the default json-to-model transform does not fit to your model object, implement
this method to do additional process. You can also use this method to validate the
model's properties.
@discussion If the model implements this method, it will be called at the end of
`+modelWithJSON:`, `+modelWithDictionary:`, `-modelSetWithJSON:` and `-modelSetWithDictionary:`.
If this method returns NO, the transform process will ignore this model.
@param dic The json/kv dictionary.
@return Returns YES if the model is valid, or NO to ignore this model.
*/
- (BOOL)modelCustomTransformFromDictionary:(NSDictionary *)dic;
複製程式碼
YYModel提供了這麼個方法,它會在+modelWithJSON:
, +modelWithDictionary:
, -modelSetWithJSON:
and -modelSetWithDictionary:
方法結束的時候呼叫。
所以我們對model特殊欄位的處理,都應該放到這個方法去執行
- (BOOL)modelCustomTransformFromDictionary:(NSDictionary *)dic{
if ([self.examSubjectName isEqualToString:@"全科"]) {
self.subjectBaseId = -100;
}
if ([self.examSubjectName isEqualToString:@"語數外"]) {
self.subjectBaseId = -200;
}
return YES;
}
複製程式碼
這麼一來,問題就解決了。
注意,YYModel還有一個- (NSDictionary *)modelCustomWillTransformFromDictionary:(NSDictionary *)dic;
這個方法很類似,但是執行的時機不一樣,這個方法是在model轉化之前執行,雖不符合本案例的需求,但是很有可能在其他類似的情況能用的上。