昨天看到一個(gè)群里的朋友的問題,接手一個(gè)已有項(xiàng)目的歷史遺留bug:項(xiàng)目已經(jīng)完成,代碼量很大,有很多自定義模型類,并且模型類直接存在各種嵌套,之前的模型類所有關(guān)于服務(wù)器返回的數(shù)字都是統(tǒng)一用NSString存儲(chǔ)的,但是后臺(tái)返回的并不是字符串,導(dǎo)致了YYModel字典轉(zhuǎn)模型的時(shí)候,所有模型的字符串都是這樣:
NSDictionary *dict = @{
@"fee": [NSNumber numberWithDouble:807.69],
@"firend":@{
@"fee": [NSNumber numberWithDouble:807.69]
}
};
后臺(tái)返回的數(shù)字:807.69
// 類似的模型類
@interface Person : NSObject
@property(nonatomic, strong) NSString *fee;
@property(nonatomic, strong) Person *friend;
@end
YYModel字典轉(zhuǎn)模型后的字符串:p.friend.fee = @"807.6900000000001"
修改起來麻煩的情況在于:后臺(tái)有大量的不同字段名的數(shù)據(jù)都是這樣返回的,而且存在模型套模型、模型套模型數(shù)組這些情況,無論是客戶端改模型類的類型,還是后臺(tái)改,都是一個(gè)很大的工作量,需要改項(xiàng)目中特別多的地方,改起來又需要重新依次測(cè)試,非常的耗時(shí)間。
最后我還是想到了一個(gè)最取巧的辦法,不需要去改動(dòng)項(xiàng)目的任何代碼,只需要?jiǎng)?chuàng)建一個(gè)分類文件,用runtime方法交換,在YYModel通過字典給模型賦值數(shù)據(jù)的方法之前,先將字典的NSNumber類型轉(zhuǎn)成不損失精度的NSString,在尾部去0,重新傳給YYModel原來的方法就行了。
只需要將下面這個(gè)分類文件添加到項(xiàng)目中,就可以解決這個(gè)問題。這樣后臺(tái)和客戶端都不需要改任何項(xiàng)目源代碼,實(shí)現(xiàn)了對(duì)項(xiàng)目源代碼的0入侵。
源碼:
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSObject (ModelExchange)
@end
NS_ASSUME_NONNULL_END
#import "NSObject+ModelExchange.h"
#import "NSObject+YYModel.h"
#import <objc/runtime.h>
@implementation NSObject (ModelExchange)
+ (void)load {
Method method1 = class_getInstanceMethod([self class], @selector(yy_modelSetWithDictionary:));
Method method2 = class_getInstanceMethod([self class], @selector(my_modelSetWithDictionary:));
method_exchangeImplementations(method1, method2);
}
- (BOOL)my_modelSetWithDictionary:(NSDictionary *)dic {
NSMutableDictionary *mDictionary = [NSMutableDictionary dictionary];
[dic enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
if ([obj isKindOfClass:[NSNumber class]]) {
NSNumber *num = (NSNumber *)obj;
NSNumberFormatter *formatter = [NSNumberFormatter new];
formatter.numberStyle = NSNumberFormatterDecimalStyle;
[formatter setGroupingSeparator:@""];
NSString *str = [formatter stringFromNumber:num];
[mDictionary setValue:str forKey:key];
} else {
[mDictionary setValue:obj forKey:key];
}
}];
return [self my_modelSetWithDictionary:mDictionary];
}
@end