平时程序中遇到的crash(一)

 NO.1:NSInvalidArgumentException 异常

出现这个crash的原因较多,选取了几个崩溃次数较多的crash.

crash日志1:

-[__NSPlaceholderDictionary initWithObjects:forKeys:count:]: attempt to insert nil object from objects[1]'

crash日志拿到了,怎么复现该现象呢?我们看到initWithObjects:forKeys:count:,猜测一下应该是NSDictionary初始化时的问题,在看后面的提示attempt to insert nil object,此时就可以做一个猜测,应该是NSDictionary初始化时插入nil对象造成的异常。下面我们写一段代码来验证一下:


运行后崩溃的信息如下:


上面的崩溃信息验证我们的想法,为什么会出现这种现象呢?如何解决这样的crash呢?

在转换成NSDictionary的过程中,后台返回的数据有时可能为空,就会造成插入nil对象,从而导致crash。

目前个人知道的解决办法:

1.后台在返回数据的时候进行校验,对空值进行处理。但是在项目中有些空值是有特殊的用途,此种方案不可行。

2.在转换成NSDictionary的时候,对后台返回的数据进行校验,把空值转换成NSNull对象。方案可行,但是需要对现有代码做大的改动,每次转换的时候都需要进行校验,太麻烦。业务高速发展时期,这样做成本太高。

3.有没有一种无须改动现有代码又能解决该问题呢?答案是有的,可以利用Objective-C的runtime来解决该问题

NSDictionary插入nil对象会造成崩溃,但是插入NSNull对象是不会造成崩溃的,只要利用runtime的Swizzle Method把nil对象给转换成NSNull对象就可以把该问题给解决了。创建一个NSDictionary的类别,利用runtime的Swizzle Method来替换系统的方法。源码实现可以参考Glow团队封装的NSDictionary+NilSafe(Github上可下载到), 全部源码会在文章末尾提供

crash 日志2

data parameter is nil

NSData *data = nil;
NSError *error;
NSDictionary *orginDict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
NSLog(@ "originDict is : %@" , orginDict);
运行后,崩溃信息如下:


这个问题比较好解决,在序列化的时候,统一加入判断,判断data是不是nil即可。

crash 日志3

1
unrecognized selector sent to instance 0x15d23910

造成这条崩溃的原因,想必大家都比较熟悉了,就是一个类调用了一个不存在的方法,造成的崩溃。解决这样的问题,可以在写一个方法的时候,判断一下其类的类型,不符合类型的不让其调用,也可以使用runtime对常见的方法调用做一下错误兼容。比如我这边经常会出现这样的崩溃:

1
2
3
4
-[__NSCFConstantString objectForKeyedSubscript:]: unrecognized selector sent to instance 0x1741af420
-[NSNull length]: unrecognized selector sent to instance 0x1b21e6ef8    
-[__NSCFConstantString objectForKeyedSubscript:]: unrecognized selector sent to instance
-[__NSDictionaryI length]: unrecognized selector sent to instance 0x174264500

当这些对象调用这几个不存在的方法的时候,替换成自己定义的一个方法,对它们做一下错误兼容,使应用不会崩溃。现截取部分代码实现,全部源码会在文章末尾提供。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@implementation NSString (NSRangeException)
 
+ (void)load{
     static dispatch_once_t onceToken;
     dispatch_once(&onceToken, ^{
         @autoreleasepool {
             [objc_getClass( "__NSCFConstantString" ) swizzleMethod:@selector(objectForKeyedSubscript:) swizzledSelector:@selector(replace_objectForKeyedSubscript:)];
         }
     });
}
 
- (id)replace_objectForKeyedSubscript:(NSString *)key {
     return  nil;
}
 
@end

小结一下,造成NSInvalidArgumentException异常大概有以下原因:

  • NSDictionary插入nil的对象。NSMutableDictionary也是同样的道理。

  • NSJSONSerialization序列化的时候,传入data为nil。

  • an unrecognized selector 无法识别的方法







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值