美文网首页iOS-开发随笔
Invalid number value (infinite)

Invalid number value (infinite)

作者: 小小棒棒糖 | 来源:发表于2022-05-06 21:07 被阅读0次

    背景

    线上崩溃排查中,发现一批model转JSON时发生崩溃,描述如下:

    崩溃信息

    Invalid number value (infinite) in JSON write
    XXXX -[NSObject(YYModel) modelToJSONData] (NSObject+YYModel.m:)

    崩溃原因

    INFINITY:无穷
    NAN:不是数字
    使用系统解析方法NSJSONSerialization解析JSON时,会发生崩溃(如上崩溃日志)。

    为什么会产生NAN/INFINITY?

    1. App作图记录,是全平台的互通的,JS或其它语言支持NAN数字
    2. 未知原因混进来或错误生成一些NAN,INFINITY数据

    注:
    浮点数类型除以0 产生 +inf
    错误开方产生NaN

    image.png

    如何防护

    ios提供了检测无效数字的函数

    1. isnan(number)
    2. isinf(number)

    在YYModel中,已经添加了对无效数字的检测(第6行),为什么还是崩了呢?

    static id ModelToJSONObjectRecursive(NSObject *model) {
        if (!model || model == (id)kCFNull) return model;
        if ([model isKindOfClass:[NSString class]]) return model;
        if ([model isKindOfClass:[NSNumber class]]) {
            double doubleValue = ((NSNumber *)model).doubleValue;
            if (isnan(doubleValue) || isinf(doubleValue)) {
                return @(0);
            }
            return model;
        }
    ...
    ...
        // Set解析同样
        // 数组解析
        if ([model isKindOfClass:[NSArray class]]) {
            if ([NSJSONSerialization isValidJSONObject:model]) return model;
            NSMutableArray *newArray = [NSMutableArray new];
            for (id obj in (NSArray *)model) {
                if ([obj isKindOfClass:[NSString class]] || [obj isKindOfClass:[NSNumber class]]) {
                    [newArray addObject:obj];
                } else {
                    id jsonObj = ModelToJSONObjectRecursive(obj);
                    if (jsonObj && jsonObj != (id)kCFNull) [newArray addObject:jsonObj];
                }
            }
            return newArray;
        }
    }
    

    上面的解析,对于dict中value为Number类型,@{key: @(NAN)},确实已经通过if (isnan(doubleValue) || isinf(doubleValue))返回0避免崩溃。
    但当value为数组,数组内包含无效数字时,@{@"v1": @[@(NAN),@(INFINITY)]},就直接绕过了isnan/isinf的检测(走第19行),导致解析崩溃。

    修复

    去除NSSet/NSArray中的NSNumber判定(19行),让其走isnan/isinf检测。

    static id ModelToJSONObjectRecursive(NSObject *model) {
        if (!model || model == (id)kCFNull) return model;
        if ([model isKindOfClass:[NSString class]]) return model;
        if ([model isKindOfClass:[NSNumber class]]) {
            double doubleValue = ((NSNumber *)model).doubleValue;
            if (isnan(doubleValue) || isinf(doubleValue)) {
                return @(0);
            }
            return model;
        }
    ...
    ...
        // Set解析同样
        // 数组解析
        if ([model isKindOfClass:[NSArray class]]) {
            if ([NSJSONSerialization isValidJSONObject:model]) return model;
            NSMutableArray *newArray = [NSMutableArray new];
            for (id obj in (NSArray *)model) {
                if ([obj isKindOfClass:[NSString class]]) { // 去除NSNumber判定,让其走isnan/isinf检测
                    [newArray addObject:obj];
                } else {
                    id jsonObj = ModelToJSONObjectRecursive(obj);
                    if (jsonObj && jsonObj != (id)kCFNull) [newArray addObject:jsonObj];
                }
            }
            return newArray;
        }
    }
    

    相关文章

      网友评论

        本文标题:Invalid number value (infinite)

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