今天测试app时发现一个必现的异常,当在登录成功后再打开登录前点击的页面时,就会在Xcode console中打印如下日志:
NSScanner:nil string argument
NSScanner:nil string argument
libc++abi.dylib: terminate_handler unexpectedly threw an exception
然后app就会crash掉。
搜索了一下相关资料,得知出现NSScanner: nil string argument问题都是跟字符串有关,一般认为是intWithString:的参数传入了nil就会出现这个问题。但是项目的代码中并没有几处intWithString:的地方,逐一加断点都排除了出问题的可能。
然后我单步调试,发现问题可能出在这几行代码:
NSDictionary *para=nil;
para=@{@"userid":[Configs getInstance].me.uid, @"flag":@"1" };
那么最有问题的可能在这里:[Configs getInstance].me.uid,会不会在它为nil时出现上面的crash问题呢?经过验证,在出现crash之前这个uid值果然为nil,又是前人留下的坑……对代码进行了一些调整,此问题解决。
20150411更新:
出现NSScanner:nil string argument这个问题很有可能是因为你在项目中用了友盟的SDK,这样的错误信息非常不利于定位,可以先把调用友盟SDK的代码注释掉来定位问题。
20151119更新:
这篇文章libc++abi.dylib: terminate_handler unexpectedly threw an exception错误小结 对这个问题进行了一些分析:
现在唯一的信息点是libc++abi.dylib,这个库到底是做什么的?从后缀看,是一个动态库,那么会不会是因为发生了一些动态错误?而按经验来看,一般的动态错误基本是因为动态类型错误引起,在object-c语言中,会发生动态类型错误的可能基本存在于不可变类型与可变类型之间的转换,那么我们的查错范围将优先限制在不可变类型与可变类型转换上,是否我们对一个不可变类型进行了修改操作?当然,编译器没有那么傻,如果直接对一个不可变类型进行修改操作,是会直接报错的,那么就剩下另一种可能,程序将一个不可变类型赋值给可变类型,然后对可变类型进行了修改操作,这样可以通过静态检查,但是动态运行的时候,就会发生类型错误。基于以上分析,我们可以跟踪断点,会发现程序在对mutable对象进行add、set等操作时挂掉,而这个对象实际上赋值的是一个不可变对象。常见的情况是把一个NSArray对象赋值给一个NSMutableArray对象,然后进行了delete、add等修改操作,或者把一个NSDictionary对象赋值给一个NSMutableDictionary对象,然后进行了set等操作。
然而我今天又遇到这样的问题,单步调试发现crash发生在dequeueReusableCellWithIdentifier:方法这里。定位到最后才发现在代码里把一个IBOutlet改名了,但是xib里这个改名前的IBOutlet还存在,去掉改名前的IBOutlet就解决问题了。
20151203更新:
遇到这种错误:
-[__NSArrayI length]: unrecognized selector sent to instance 0x1686d110
[;libc++abi.dylib: terminate_handler unexpectedly threw an exception
正常情况下用Xcode Debug是看不到这发生crash的位置的,只知道是某个字符串变成了NSArray呢?怎么快速定位呢,拔掉数据线,再重现一次Crash,然后再连接数据线,选择Xcode菜单上的Window——Devices,在左侧列表找到设备名,点击其右的View Device Logs,定位到刚刚发生的crash log,点右键选择Re-Symbolicate Log,稍等片刻你就可以解析后的Crash log了,这个时候就很容易看到crash发生的代码行了。
今天用PushViewController时又遇到这种错误,原因是新建了一个VC,没用Xib,后来又想用Xib于是又单独新建了一个Xib,但是没有把File's Owner中的View属性与View关联,就报了libc++abi.dylib: terminate_handler unexpectedly threw an exception这种错了。
参考:
UITableView删除的时候崩溃NSScanner:nil string argument