iOS中常常遇到后端返回JSON出现null值问题

在iOS开发过程中经常需要与服务器进行数据通讯,Json就是一种常用的高效简洁的数据格式。往往后端返回的数据会出现null值,会被解析成NSNull对象,直接调用字符串 / 数组 / 字典方法会直接崩溃。如下:

json 复制代码
"data":null

解决方法有两个

第一个解决方案:

通过写宏进行值替换

ini 复制代码
#define VerifyValue(value)
({id tmp;
if ([value isKindOfClass:[NSNull class]])
tmp = nil;
else
tmp = value;
tmp;
})

第二个解决方案:

使用AFNetwork自带的方法解决

(终极方案终于找到了一劳永逸的方案,牛逼的老外写了一个Category,叫做NullSafe ,在运行时操作,把这个讨厌的空值置为nil,而nil是安全的,可以向nil对象发送任何message而不会奔溃。这个category使用起来非常方便,只要加入到了工程中就可以了,你其他的什么都不用做,对,就是这么简单)

ruby 复制代码
self.removesKeysWithNullValues = YES;

5、终极方案终于找到了一劳永逸的方案,牛逼的老外写了一个Category,叫做NullSafe ,在运行时操作,把这个讨厌的空值置为nil,而nil是安全的,可以向nil对象发送任何message而不会奔溃。这个category使用起来非常方便,只要加入到了工程中就可以了,你其他的什么都不用做,对,就是这么简单。详细的请去Github上查看;[https://github.com/nicklockwood/NullSafe](https://github.com/nicklockwood/NullSafe)

第三个解决方案:

通过NSJSONSerialization调用JSONObjectWithData方法

ini 复制代码
// 1. 解析后端JSON
NSDictionary *originalDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
// 2. 一键替换所有 null → ""
NSDictionary *safeDict = [originalDict replaceNullWithEmptyString];
// 3. 永远不会因为 null 崩溃
NSString *name = safeDict[@"name"]; 

第四个解决方案:

纯字符串场景:用正则替换 null 为 "",如果后端返回的是原始 JSON 字符串,里面直接写了null,可以用正则表达式全局替换: 正则规则 匹配独立的 null 单词(避免误替换包含 null 的单词):

swift 复制代码
// 原始后端返回字符串
NSString *jsonString = @"{\"name\":null,\"age\":18,\"address\":\"null street\"}";

// 正则替换:所有独立的 null 替换为空字符串 ""
NSError *error = nil;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"\\bnull\\b"
                                                                       options:0
                                                                         error:&error];
NSString *result = [regex stringByReplacingMatchesInString:jsonString
                                                  options:0
                                                    range:NSMakeRange(0, jsonString.length)
                                             withTemplate:@"\"\""];

NSLog(@"替换后:%@", result);

第五个解决方案:

写一个类目(Category),递归遍历字典 / 数组,把所有 NSNull 替换成 @""

  1. 给 NSDictionary 写类目(最实用) NSDictionary+NullReplace.h
objectivec 复制代码
#import <Foundation/Foundation.h>
@interface NSDictionary (NullReplace)
- (NSDictionary *)replaceNullWithEmptyString;
@end

NSDictionary+NullReplace.m

objectivec 复制代码
#import "NSDictionary+NullReplace.h"

@implementation NSDictionary (NullReplace)

- (NSDictionary *)replaceNullWithEmptyString {
    NSMutableDictionary *mutDict = [self mutableCopy];
    
    // 遍历所有key
    [mutDict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
        // 1. 如果是 NSNull → 替换为空字符串
        if ([obj isKindOfClass:[NSNull class]]) {
            mutDict[key] = @"";
        }
        // 2. 如果是子字典 → 递归处理
        else if ([obj isKindOfClass:[NSDictionary class]]) {
            mutDict[key] = [obj replaceNullWithEmptyString];
        }
        // 3. 如果是数组 → 单独处理数组
        else if ([obj isKindOfClass:[NSArray class]]) {
            mutDict[key] = [obj replaceNullWithEmptyString];
        }
    }];
    
    return [mutDict copy];
}
@end
  1. 给 NSArray 写类目 NSArray+NullReplace.h
objectivec 复制代码
#import <Foundation/Foundation.h>
@interface NSArray (NullReplace)
- (NSArray *)replaceNullWithEmptyString;
@end

NSArray+NullReplace.m

ini 复制代码
#import "NSArray+NullReplace.h"
#import "NSDictionary+NullReplace.h"

@implementation NSArray (NullReplace)

- (NSArray *)replaceNullWithEmptyString {
    NSMutableArray *mutArray = [self mutableCopy];
    
    // 遍历数组元素
    for (int i = 0; i < mutArray.count; i++) {
        id obj = mutArray[i];
        
        if ([obj isKindOfClass:[NSNull class]]) {
            mutArray[i] = @"";
        }
        else if ([obj isKindOfClass:[NSDictionary class]]) {
            mutArray[i] = [obj replaceNullWithEmptyString];
        }
        else if ([obj isKindOfClass:[NSArray class]]) {
            mutArray[i] = [obj replaceNullWithEmptyString];
        }
    }
    
    return [mutArray copy];
}
@end

总结

  1. 后端返回的null → iOS 解析为NSNull,正则无法处理
  2. 递归替换类目 是 iOS 开发处理 null 的标准方案
  3. 正则只适合原始 JSON 字符串预处理
  4. 导入类目后,一行代码就能彻底解决崩溃问题
相关推荐
@大迁世界1 天前
Firefox 本地模式:localhost 再见了 ?
前端·架构
米米商聊1 天前
同名附件为什么被 Map 覆盖?重复键与一对多索引
前端·javascript
echome8881 天前
Python 异常处理:try、else、finally 的正确搭配
开发语言·前端·python·异常处理·编程技巧
时间的情敌1 天前
OpenLayers 实战|Vue3 + OpenLayers 完整工程案例(加载天地图、要素、弹窗、绘制、WFS)
前端·openlayers
陈随易1 天前
下载神器!Motrix 停更三年后重写回归
前端·后端·程序员
前端的日常1 天前
一个人+AI做情侣食谱小程序,0 费用的服务器
前端·后端
计算机魔术师1 天前
谷歌搜索广告踩刹车,AI广告成为救命稻草
前端
总要学点什么1 天前
第81篇:数据可视化-PM2.5分布——让圆点的胖瘦替每座城市报出浓度
前端·信息可视化·echarts·cesium·空间分析
IT_陈寒1 天前
Vue的v-for里用了个临时变量,页面直接挂了
前端·人工智能·后端
hunter_0761 天前
一次 iOS 真机签名 409 的完整排查:证书、设备、描述文件为什么总是"对不上"
前端