文档章节

ios中json解析出现的null问题

余成海
 余成海
发布于 2015/04/29 13:08
字数 794
阅读 28987
收藏 12

在iOS开发过程中经常需要与服务器进行数据通讯,Json就是一种常用的高效简洁的数据格式。

问题现象

但是几个项目下来一直遇到一个坑爹的问题,程序在获取某些数据之后莫名崩溃。其实很早就发现了原因:由于服务器的数据库中有些字段为空,然后以Json形式返回给客户端时就会出现这样的数据:

"somevalue":null

通过JsonKit 这个第三方库解析出来的数据就成了

somevalue = "<null>";

这个数据类型不是nil 也不是 String。 解析成对象之后,如果直接向这个对象发送消息(eg:length,count 等等)就会直接崩溃。提示错误为:

 -[NSNull length]: unrecognized selector sent to instance 0x388a4a70

解决方法

其实一直没有找到完美的解决办法,坑了我很久。

1、最开始的解决方法就是为了应付当前遇到的崩溃,看看哪个字段可能为空,那么就对该字段使用前进行判断,通过崩溃时的错误提示可以看出,这样的字段解析成的对象是 NSNull 类型的,所以可以直接判断是不是此类型:

 if (![isKindOfClass:[NSNull class]]){xxxxxxx;}

因为字段实在太多,就找一个补一个。

2、后来想彻底解决这问题,就打算从数据源下手,其实应该可以用正则表达式匹配这个null ,然后进行替换,奈何正则是我的硬伤啊。于是就相出了一个山寨方法:字符串匹配。在获取到服务器返回的Json时,返回结果时string对象,于是就先替换 null 为 为空字符””,然后再解析。

json = [jsonStr  stringByReplacingOccurrencesOfString:@":null" withString:@":\"\""];

这个方法本来很奏效,但是我这里的服务器返回极不简洁,各种垃圾数据(不吐槽这了)。。。反正这样会导致json无法解析了。

3、最后没有办法,只能在解析的时候下手,把是NSNull 类型的值替换成nil。 一般就写个tool方法,然后解析时调用。但是嫌太麻烦,就想弄写个宏,通过搜索惊奇的发现宏也是可以有返回值的,结果如下:

#define VerifyValue(value)\
({id tmp;\
if ([value isKindOfClass:[NSNull class]])\
tmp = nil;\
else\
tmp = value;\
tmp;\
})\

宏里的最后一句语句便是返回值。然后在解析数据时调用宏:

contact.contactPhone = VerifyValue(contactDic[@"send_ContactPhone"]);

4、如果你使用AFNetwork 这个库做网络请求的话,可以用以下代码,自动帮你去掉这个讨厌的空值

self.removesKeysWithNullValues = YES;

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


本文转载自:http://www.pan-apps.com/668.html

余成海
粉丝 62
博文 57
码字总数 29577
作品 0
杭州
iOS工程师
私信 提问
加载中

评论(14)

m
moonwinter

引用来自“moonwinter”的评论

请问下你的第四种解决方案,那句代码是写在哪里的?

引用来自“余成海”的评论

写在网络调用前面

引用来自“moonwinter”的评论

麻烦下能具体说明吗,我发现这个是afn中AFJSONResponseSerializer类的一个属性,而manager.responseSerializer是其父类类型AFHTTPResponseSerializer,你是直接使用self调用这个属性,不明白这个具体怎么使用,谢谢!

引用来自“余成海”的评论

百度搜索一下有很多实例的啊,我贴一个给你看
AFHTTPSessionManager *session = [AFHTTPSessionManager manager];
((AFJSONResponseSerializer *)session.responseSerializer).removesKeysWithNullValues = YES;
session.responseSerializer = [AFHTTPResponseSerializer serializer];
//session.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json",@"text/json", @"text/javascript",@"text/plain",@"text/html",nil];
session.securityPolicy = [self customSecurityPolicy];

[session POST:urlStr parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
if (success) {
success(responseObject);
NSLog(@"外部失败");
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
if (fail) {
fail();
NSLog(@"内部失败");
}
}];
OK,多谢了
余成海
余成海 博主

引用来自“moonwinter”的评论

请问下你的第四种解决方案,那句代码是写在哪里的?

引用来自“余成海”的评论

写在网络调用前面

引用来自“moonwinter”的评论

麻烦下能具体说明吗,我发现这个是afn中AFJSONResponseSerializer类的一个属性,而manager.responseSerializer是其父类类型AFHTTPResponseSerializer,你是直接使用self调用这个属性,不明白这个具体怎么使用,谢谢!
百度搜索一下有很多实例的啊,我贴一个给你看
AFHTTPSessionManager *session = [AFHTTPSessionManager manager];
((AFJSONResponseSerializer *)session.responseSerializer).removesKeysWithNullValues = YES;
session.responseSerializer = [AFHTTPResponseSerializer serializer];
//session.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json",@"text/json", @"text/javascript",@"text/plain",@"text/html",nil];
session.securityPolicy = [self customSecurityPolicy];

[session POST:urlStr parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
if (success) {
success(responseObject);
NSLog(@"外部失败");
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
if (fail) {
fail();
NSLog(@"内部失败");
}
}];
m
moonwinter

引用来自“moonwinter”的评论

请问下你的第四种解决方案,那句代码是写在哪里的?

引用来自“余成海”的评论

写在网络调用前面
麻烦下能具体说明吗,我发现这个是afn中AFJSONResponseSerializer类的一个属性,而manager.responseSerializer是其父类类型AFHTTPResponseSerializer,你是直接使用self调用这个属性,不明白这个具体怎么使用,谢谢!
余成海
余成海 博主

引用来自“moonwinter”的评论

请问下你的第四种解决方案,那句代码是写在哪里的?
写在网络调用前面
m
moonwinter
请问下你的第四种解决方案,那句代码是写在哪里的?
余成海
余成海 博主

引用来自“枫_林_海”的评论

大神问个问题:这个可以在服务端处理不???是IOS端平台差异照成的还是服务端的问题?
可以在服务器处理的,java语言和oc语言的语法不同造成的,只是服务器处理起来麻烦一些
枫_林_海
枫_林_海
大神问个问题:这个可以在服务端处理不???是IOS端平台差异照成的还是服务端的问题?
枫_林_海
枫_林_海
这个可以在服务端处理不???是IOS端平台差异照成的还是服务端的问题?
余成海
余成海 博主

引用来自“JDYang”的评论

我的页面进入商品详情页 那些有价格的商品如果网络慢的话就会显示null.很难看我不想显示null请问怎么处理呢?
你的情况和我说的博客不是一回事,网络慢显示null是因为你的nsstring的值是nill,通过界面打印出来就会显示null,你可以将string初始化成空字符串就能解决问题了
JDYang
JDYang

引用来自“SunnyPeng”的评论

你好,按照5终极方案, 我下载了NullSafe这个库,把NullSafe.m文件导入了,还是不行,这个文件根本就不会走。 请问楼主怎么弄的
1楼你解决了吗?
ios中应用Lottie解决动画问题

作为一名iOS工程师,深知复杂动画的痛苦,下面我们来介绍下Lottie来解决日常的动画难题。 Lottie的简单介绍: 使用Lottie开发的流程是: 设计师在AE中设计完成你的动画,通过bodymoving插件导...

威廉云霄
02/20
0
0
aes256 java 加密, IOS解密

@Nic_Sun 你好,想跟你请教个问题:我看了你的例子,自己写了一遍,Java可以加密,解密, ios也可以加密,解密,但是, java加密出来的byte[]类型的数据,怎么传到ios端,用json吗, 如果是j...

zhuguoqiang
2014/08/06
833
2
IOS下WEBVIEW 的javascript数组与json定义 及交互

最近在折腾IOS新闻浏览客户端,当中需要用到webview传递JSON数据到IOS上,然后在IOS上解析。刚入门IOS不久,看了不少的书,但都是囫囵吞枣。在开发过程中,遇到不少问题。 开发环境 mac mini...

GIFCOOL
2013/08/20
4K
0
If love, deep love:10 Most Useful iOS Libs

摘要:库是开发的根本,从页面到APP客户端,所有的设计都离不开它,但面对市面上鱼龙混杂的库,如何选择合适又好用的库?对开发新手来说,这是个问题。本文基于各方观点,选出了10大iOS开发者...

长平狐
2013/01/06
90
0
基于原生的移动跨平台研究和实践

基于原生主要是针对基于webview+h5比较来说的,基于H5的我不想再讨论了,我想尝试的是从UI到功能都是原生,而不是用H5模拟的所谓原生体验。 背景 我们从开发角度来考虑,但凡想从事长远的开发...

voxer
2017/03/26
135
0

没有更多内容

加载失败,请刷新页面

加载更多

64.监控平台介绍 安装zabbix 忘记admin密码

19.1 Linux监控平台介绍 19.2 zabbix监控介绍 19.3/19.4/19.6 安装zabbix 19.5 忘记Admin密码如何做 19.1 Linux监控平台介绍: 常见开源监控软件 ~1.cacti、nagios、zabbix、smokeping、ope...

oschina130111
昨天
64
0
当餐饮遇上大数据,嗯真香!

之前去开了一场会,主题是「餐饮领袖新零售峰会」。认真听完了餐饮前辈和新秀们的分享,觉得获益匪浅,把脑子里的核心纪要整理了一下,今天和大家做一个简单的分享,欢迎感兴趣的小伙伴一起交...

数澜科技
昨天
26
0
DNS-over-HTTPS 的下一代是 DNS ON BLOCKCHAIN

本文作者:PETER LAI ,是 Diode 的区块链工程师。在进入软件开发领域之前,他主要是在做工商管理相关工作。Peter Lai 也是一位活跃的开源贡献者。目前,他正在与 Diode 团队一起开发基于区块...

红薯
昨天
43
0
CC攻击带来的危害我们该如何防御?

随着网络的发展带给我们很多的便利,但是同时也带给我们一些网站安全问题,网络攻击就是常见的网站安全问题。其中作为站长最常见的就是CC攻击,CC攻击是网络攻击方式的一种,是一种比较常见的...

云漫网络Ruan
昨天
27
0
实验分析性专业硕士提纲撰写要点

为什么您需要研究论文的提纲? 首先当您进行研究时,您需要聚集许多信息和想法,研究论文提纲可以较好地组织你的想法, 了解您研究资料的流畅度和程度。确保你写作时不会错过任何重要资料以此...

论文辅导员
昨天
44
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部