美文网首页
部分小数类型NSNumber转NSString失精问题的思考和解

部分小数类型NSNumber转NSString失精问题的思考和解

作者: ask_ME | 来源:发表于2019-08-19 16:34 被阅读0次

由于公司后台数据部分json数据格式为float,导致json转为字典中float对应类型NSNumber极有可能会失精.主要原因在于iOSjson解析库将数值类型解析成为long或者double类型,然后再格式转换为number.
根本原因在于 numberdescription 方法转成字符串会失精,目前尝试过重写 NSNumber 或作者其元类的description方法,并没有走这个方法.有哪位盆友知晓请不吝赐教。肯定比下面方法更好啦!
话说Andriod完全ok

重要的事情说三遍: json数据请用万能的字符串

补充:iOS13 字面量取值又失精了(需替换objectForKeyedSubscript:

测试数据举例: @(90.01)

NSLog(@"%@",@(90.01));  // 90.01000000000001

由于需要修改的地方较多,所以创建NSDictinary分类,直接覆盖objectForKey方法

#import "NSDictionary+extend.h"
#import <objc/runtime.h>
@implementation NSDictionary (extend)

+ (void)exchangeInstanceMethod:(Class)anClass method1Sel:(SEL)originalSEL method2Sel:(SEL)SwizzledSEL{

    Method originalMethod = class_getInstanceMethod(anClass, originalSEL);
    Method SwizzledMethod = class_getInstanceMethod(anClass, SwizzledSEL);

    IMP originalIMP = method_getImplementation(originalMethod);
    IMP SwizzledIMP = method_getImplementation(SwizzledMethod);
    
    Class class = [self class];
    BOOL isSuccess = class_addMethod(class, originalSEL, SwizzledIMP, method_getTypeEncoding(SwizzledMethod));
    
    if (isSuccess) {
        class_replaceMethod(class, SwizzledSEL, originalIMP, method_getTypeEncoding(originalMethod));
    }else{
        method_exchangeImplementations(originalMethod, SwizzledMethod);
    }
}

+ (void) load{

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        SEL originalSEL = @selector(objectForKey:);
        SEL SwizzledSEL = @selector(my_objectForKey:);
        // __NSDictionaryI 为 NSDictionary 在内存中对应的元类
        [self exchangeInstanceMethod:NSClassFromString(@"__NSDictionaryI") method1Sel:originalSEL method2Sel:SwizzledSEL];
        //  iOS13
        SEL originalSELSubscript = @selector(objectForKeyedSubscript:);
        SEL SwizzledSELSubscript = @selector(my_objectForKeyedSubscript:);
        [self exchangeInstanceMethod:NSClassFromString(@"__NSDictionaryI") method1Sel:originalSELSubscript method2Sel:SwizzledSELSubscript];
    });
}

- (id)my_objectForKey:(id)aKey{

    id object = [self my_objectForKey:aKey];

    if ([object isKindOfClass:[NSNumber class]]) {

        if (strcmp( type, @encode(double)) == 0) {

            NSString * doubleStr = [NSString stringWithFormat:@"%f", [(NSNumber *)object doubleValue]];
            NSDecimalNumber * decNum = [NSDecimalNumber decimalNumberWithString:doubleStr];
            object = decNum;
        }
    }
    return object;
}
// 适配 iOS13,需要替换字面量方法
 - (id)my_objectForKeyedSubscript:(id)aKey{
    id object = [self my_objectForKeyedSubscript:aKey];
    if ([object isKindOfClass:[NSNumber class]]) {
        const char * type = [object objCType];
        if (strcmp( type, @encode(double)) == 0) {
            NSString * doubleStr = [NSString stringWithFormat:@"%f", [(NSNumber *)object doubleValue]];
            NSDecimalNumber * decNum = [NSDecimalNumber decimalNumberWithString:doubleStr];
            object = decNum;
        }
    }
    return object;
}

大功告成啦~~~
说多了都是眼泪,相信大家使用MJExtension的同学还是很多的,发现此方法在iOS10是可以的,然而iOS12就沙雕了,所以我又改了MJExtension源码(竟然是核心代码).

@implementation NSObject (MJKeyValue)
/**
 核心代码:
 */
- (instancetype)mj_setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context
    if (propertyClass == [NSString class]) {

                    // NSNumber -> NSString
                    if ([value isMemberOfClass:[NSDecimalNumber class]]) {
                        value = [value description];
                    }else if ([value isKindOfClass:[NSNumber class]]){
                        NSString * temp = [NSString stringWithFormat:@"%lf",[(NSNumber *)value doubleValue]];
                        value = [NSDecimalNumber decimalNumberWithString:temp].stringValue;
                    } else if ([value isKindOfClass:[NSURL class]]) {
                        // NSURL -> NSString
                        value = [value absoluteString];
                    }
                    
//                    以下是修改前的代码

//                    // NSNumber -> NSString
//                    if ([value isKindOfClass:[NSNumber class]]){
//                        value = [value description];
//                    } else if ([value isKindOfClass:[NSURL class]]) {
//                        // NSURL -> NSString
//                        value = [value absoluteString];
//                    }
                }
}
@end

相关文章

网友评论

      本文标题:部分小数类型NSNumber转NSString失精问题的思考和解

      本文链接:https://www.haomeiwen.com/subject/svxesctx.html