diff --git a/MJExtension/NSObject+MJKeyValue.m b/MJExtension/NSObject+MJKeyValue.m index 1515d229..43d93e7d 100755 --- a/MJExtension/NSObject+MJKeyValue.m +++ b/MJExtension/NSObject+MJKeyValue.m @@ -16,6 +16,26 @@ #import "NSString+MJExtension.h" #import "NSObject+MJClass.h" +@implementation NSDecimalNumber(MJKeyValue) + +- (id)standardValueWithTypeCode:(NSString *)typeCode { + // 由于这里涉及到编译器问题, 暂时保留 Long, 实际上在 64 位系统上, 这 2 个精度范围相同, + // 32 位略有不同, 其余都可使用 Double 进行强转不丢失精度 + if ([typeCode isEqualToString:MJPropertyTypeLongLong]) { + return @(self.longLongValue); + } else if ([typeCode isEqualToString:MJPropertyTypeLongLong.uppercaseString]) { + return @(self.unsignedLongLongValue); + } else if ([typeCode isEqualToString:MJPropertyTypeLong]) { + return @(self.longValue); + } else if ([typeCode isEqualToString:MJPropertyTypeLong.uppercaseString]) { + return @(self.unsignedLongValue); + } else { + return @(self.doubleValue); + } +} + +@end + @implementation NSObject (MJKeyValue) #pragma mark - 错误 @@ -138,54 +158,53 @@ - (instancetype)mj_setKeyValues:(id)keyValues context:(NSManagedObjectContext *) } else { // 字典数组-->模型数组 value = [objectClass mj_objectArrayWithKeyValuesArray:value context:context]; } - } else { - if (propertyClass == [NSString class]) { - if ([value isKindOfClass:[NSNumber class]]) { - // NSNumber -> NSString - value = [value description]; - } else if ([value isKindOfClass:[NSURL class]]) { - // NSURL -> NSString - value = [value absoluteString]; + } else if (propertyClass == [NSString class]) { + if ([value isKindOfClass:[NSNumber class]]) { + // NSNumber -> NSString + value = [value description]; + } else if ([value isKindOfClass:[NSURL class]]) { + // NSURL -> NSString + value = [value absoluteString]; + } + } else if ([value isKindOfClass:[NSString class]]) { + if (propertyClass == [NSURL class]) { + // NSString -> NSURL + // 字符串转码 + value = [value mj_url]; + } else if (type.isNumberType) { + NSString *oldValue = value; + + // NSString -> NSDecimalNumber, 使用 DecimalNumber 来转换数字, 避免丢失精度以及溢出 + NSDecimalNumber *decimalValue = [NSDecimalNumber decimalNumberWithString:oldValue locale:nil]; + + // 检查特殊情况 + if (decimalValue == NSDecimalNumber.notANumber) { + value = @(0); + }else if (propertyClass != [NSDecimalNumber class]) { + value = [decimalValue standardValueWithTypeCode:type.code]; + } else { + value = decimalValue; } - } else if ([value isKindOfClass:[NSString class]]) { - if (propertyClass == [NSURL class]) { - // NSString -> NSURL - // 字符串转码 - value = [value mj_url]; - } else if (type.isNumberType) { - NSString *oldValue = value; - - // NSString -> NSNumber - if (type.typeClass == [NSDecimalNumber class]) { - value = [NSDecimalNumber decimalNumberWithString:oldValue]; - } else { - NSDecimalNumber *decimalValue = [NSDecimalNumber decimalNumberWithString:oldValue]; - value = decimalValue == [NSDecimalNumber notANumber] ? @(0) : @(decimalValue.doubleValue); - } - - // 如果是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; - } + + // 如果是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; } } - } else if ([value isKindOfClass:[NSNumber class]] && propertyClass == [NSDecimalNumber class]){ - // 过滤 NSDecimalNumber类型 - if (![value isKindOfClass:[NSDecimalNumber class]]) { - value = [NSDecimalNumber decimalNumberWithDecimal:[((NSNumber *)value) decimalValue]]; - } } - - // value和property类型不匹配 - if (propertyClass && ![value isKindOfClass:propertyClass]) { - value = nil; + } else if ([value isKindOfClass:[NSNumber class]] && propertyClass == [NSDecimalNumber class]){ + // 过滤 NSDecimalNumber类型 + if (![value isKindOfClass:[NSDecimalNumber class]]) { + value = [NSDecimalNumber decimalNumberWithDecimal:[((NSNumber *)value) decimalValue]]; } + } else if (propertyClass && ![value isKindOfClass:propertyClass]) { // value和property类型不匹配 + value = nil; } // 3.赋值 diff --git a/MJExtensionDemo/Base.lproj/Main.storyboard b/MJExtensionDemo/Base.lproj/Main.storyboard index 942f0bc4..75f3f5cf 100644 --- a/MJExtensionDemo/Base.lproj/Main.storyboard +++ b/MJExtensionDemo/Base.lproj/Main.storyboard @@ -1,7 +1,9 @@ - + + - + + @@ -9,16 +11,26 @@ - + - + + + + + diff --git a/MJExtensionTests/MJExtensionTests.m b/MJExtensionTests/MJExtensionTests.m index 8d823640..44b8f64c 100644 --- a/MJExtensionTests/MJExtensionTests.m +++ b/MJExtensionTests/MJExtensionTests.m @@ -30,16 +30,19 @@ - (void)testJSON2Model { NSDictionary *dict = @{ @"name" : @"Jack", @"icon" : @"lufy.png", - @"age" : @"20", + @"age" : @"2147483647", + @"age2": @"4294967295", @"height" : @1.55, - @"money" : @"100.9", + @"money" : @"100.7777777", @"sex" : @(SexFemale), @"gay" : @"1", @"speed" : @"120.5", - @"identifier" : @"3443623624362", + @"identifier" : @"9223372036854775807", + @"identifier2" : @"18446744073709551615", @"price" : @"20.3", @"rich" : @"2", - @"collect" : @"40个" + @"collect" : @"40个", + @"alien": @"yr Joking" }; // 2.将字典转为MJUser模型 @@ -48,16 +51,19 @@ - (void)testJSON2Model { // 3.检测 XCTAssert([user.name isEqual:@"Jack"]); XCTAssert([user.icon isEqual:@"lufy.png"]); - XCTAssert(user.age == 20); - XCTAssert(user.height.doubleValue == 1.55); - XCTAssert(user.money.doubleValue == 100.9); + XCTAssert(user.age == INT_MAX); + XCTAssert(user.age2 == UINT_MAX); + XCTAssert([user.height isEqualToNumber:@(1.55)]); + XCTAssert([user.money compare:[NSDecimalNumber decimalNumberWithString:@"100.7777777"]] == NSOrderedSame); XCTAssert(user.sex == SexFemale); - XCTAssert(user.gay == YES); + XCTAssert(user.gay); XCTAssert(user.speed == 120); - XCTAssert(user.identifier == 3443623624362); + XCTAssert(user.identifier == LONG_LONG_MAX); + XCTAssert(user.identifier2 == ULONG_LONG_MAX); XCTAssert(user.price == 20.3); - XCTAssert(user.rich == YES); + XCTAssert(user.rich); XCTAssert(user.collect == 40); + XCTAssert(!user.alien); } - (void)testJSON2NumberModel { diff --git a/MJExtensionTests/Model/MJUser.h b/MJExtensionTests/Model/MJUser.h index dee6bfe0..82127073 100644 --- a/MJExtensionTests/Model/MJUser.h +++ b/MJExtensionTests/Model/MJUser.h @@ -19,7 +19,8 @@ typedef enum { /** 头像 */ @property (copy, nonatomic) NSString *icon; /** 年龄 */ -@property (assign, nonatomic) unsigned int age; +@property (assign, nonatomic) int age; +@property (assign, nonatomic) unsigned int age2; /** 身高 */ @property (strong, nonatomic) NSNumber *height; /** 财富 */ @@ -32,6 +33,7 @@ typedef enum { @property (assign, nonatomic) NSInteger speed; /** 标识 */ @property (assign, nonatomic) long long identifier; +@property (assign, nonatomic) unsigned long long identifier2; /** 价格 */ @property (assign, nonatomic) double price; /** 赞 */ @@ -41,4 +43,7 @@ typedef enum { /** 富有 */ @property (assign, nonatomic) BOOL rich; +/** 一定为 NO, 用来测试无效数据 @"alien": @"yr Joking" */ +@property (assign, nonatomic) BOOL alien; + @end