iOS crash问题汇总(持续更新)

3,646 阅读5分钟

前言

对于iOS开发来说,日常空闲做得最多的事(除了摸鱼)就是解决上报的crash了。有的crash的解决还是非常考验能力的,解决完疑难crash也非常有成就感,所以笔者想记录自己在解决crash过程中的思路和历程。一是希望通过量变来提升自己的能力,二是希望其他人如果有类似的crash能提供一些解决问题的灵感。后续也会更新,甚至会把没有解决的crash也放出来,希望看到的小伙伴可以给我点建议,互相交流。

UI相关

案例一:

Exception Type: EXC_CRASH (SIGABRT)

Crashed Thread: 0 Application Specific Information:*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UICollectionViewLayoutAttributes: -setFrame: requires finite coordinates <UICollectionViewLayoutAttributes: 0x12801c1d0; index path: (0-0); frame = (0 0; 0 0)> - {{nan, 0}, {64, 64}}'

难度:✭✭✭✩✩

崩溃堆栈信息: image.png

分析: 根据堆栈不能得到有效信息。查看其用户活动页面,在其页面中找到UICollectionView,并且itemSize为 {64, 64}},可以看到是x坐标算出来一个nan的原因,cell的x坐标的计算肯定是和contetnEdge,minimumLineSpacing,查看代码发现刻意代码:

image.png 如果count为1的话分母为0计算会有问题,增加判断后,即可修复。

总结:

一个float类型的值除了一个为0的数,得到的+inf(正无穷),对于后续的对+inf的float值做的加减乘除的操作会遇到nan。

案例二:

Exception Type: EXC_CRASH (SIGABRT)

Crashed Thread: 0,Application Specific Information:*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Application tried to present modally a view controller <_SFAppAutoFillPasswordViewController: 0x10750dd10> that is already being presented by <UIKeyboardHiddenViewController_Autofill: 0x10750e2b0>.'

难度:✭✭✭✩✩

崩溃堆栈信息:

image.png

分析: 这个崩溃堆栈信息没有任何有用信息,异常原因里面有提到2个Controller,查阅资料发现是系统的,有一个是自动填充密码的。然后再通过用户页面记录看,是在登录页面,那么目前已经定位到了崩溃的页面,之后我又查看了其他几个崩溃信息,发现系统版本都是16.1.1!!难道是系统坑我?当我找到这个的时候,我确信了我内心的猜想。

image.png 苹果爸爸坑我,你不仁就别怪我不义了。

    NSString *versionStr = [UIDevice currentDevice].systemVersion;
    /// 该系统版本会产生crash,在此版本去除该功能(暂行)
    if (![versionStr isEqualToString:@"16.1.1"]) {
        _pwdTextField.secureTextEntry = YES;
     }

如果是16.1.1就暂时关闭自动填充功能。为了崩溃率,只能这样了。

内存相关

案例一:

Exception Type: EXC_BAD_ACCESS (SIGSEGV)

Crashed Thread: 0

难度:✭✭✩✩✩

崩溃堆栈信息:

image.png

崩溃代码:

image.png

分析:在刚看到这个代码的时候我非常纳闷,天王老子来了,这段代码也没毛病。直到我看到了一个非常关键的信息 ---- 这个View类没有被强引用,只是在被需要的时候add到Key Window 上了。有了这个关键的信息,其实就比较好理解了。这里使用了weakify-strongify,但self的引用计数为0,改变不了self被回收的命运,但其被回收,self.timer的内存再次被使用。就会报坏内存访问异常。

案例二

Exception Type: EXC_CRASH (SIGABRT)

Crashed Thread: 0

难度:✭✭✭✭✭✭

crash堆栈:

image.png

image.png

其他信息:

image.png

崩溃之前的页面信息:

image.png

查阅资料,发现这个 有可能是同一个问题。其中16.1.1版本的堆栈和解决方案里面的堆栈是一样的。16.5.1的堆栈是上面截图的堆栈。尝试评论区的解决方案。由于不能复现,只能等下版本上线才能看到效果。另外这种解决方案会影响交互效率,做了埋点来验证其有效性,如果不能起到防护的作用,还是要去除的。

后面又一版本发布(修复的代码没有带上去),发现这个崩溃的重灾区就是16.5.1,其次是16.1.1.

image.png 中间的2次崩溃属于分类错误,忽略不计~

------2023-08-28--------

经过了小半个月的线上验证,此bug已经修复,新版本已经没有该crash。

未解决

案例一

Exception Type: EXC_CRASH (SIGABRT)

Crashed Thread: 0,Application Specific Information:*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid parameter not satisfying: pos'

crash堆栈:

image.png

查阅资料:官方论坛

大概说的是UITextView在复制的时候有个UITextPasteDelegate需要实现。

但,我在代码里面并没有UITextView的复制相关的东西。用户行为信息显示是在启动过程中crash的。在启动的时候,App有检测系统粘贴板的操作,但感觉也没有问题的。

- (void)checkPaste {
    ZDLoginModel *m = [[ZRDataRouter sharedInstance] callDataRouterWithKey:ZDRouterLoginModel];
    if (!m) {
        return;
    }
    NSInteger count = [UIPasteboard generalPasteboard].changeCount;
    if (count == self.pasteCount) {
        return;
    }
    self.pasteCount = count;
    
    NSString *pasteStr = [UIPasteboard generalPasteboard].string;
    
    if (!pasteStr.length) {
        return;
    }
    NSLog(@"%@",pasteStr);
    
    NSString *validString = [self getValidString:pasteStr];
    if (!validString.length) {
        return;
    }
    [self getInfoWithCommand:validString];
    
}

总结

解决crash需要有一定的技术积累,对整体的业务有了解,从技术角度来说以下几点会有助于crash修复

  1. 完整解析堆栈,从我的截图可以看到,我司的APM平台并没有解析系统库的堆栈,这其实是有点不友好的。如果能把系统的也解析出来,可以更方便得和网上查阅的内容对比,从而定位问题。
  2. BI埋点,用户操作页面记录,网络日志记录。这样可以知道崩溃的具体页面。然后再根据页面内的业务逻辑去匹配问题。
  3. 合理的crash分类,通过分类可以找到一些共性,从而解决问题。