咱们苹果后台有很多的溃散上报,溃散信息如下:

Exception Type: EXC_CRASH (SIGKILL)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Termination Reason: RUNNINGBOARD 0xdead10cc

咱们也接到不少用户反馈存在溃散问题,现象便是App退到后台一段时间后,有概率溃散,有的用户反馈溃散的很频频,咱们自测又没有问题,毫无规律。由于咱们是TestFlight分发的运用,所以溃散了会特别显着,由于会弹一个“XX运用已溃散,是否上报”的体系弹框。如果是AppStore分发的运用,即便存在这个问题,或许也不容易发觉,由于你切到其他运用,再切回来发现运用重启了,你也无法分辩是体系正常的杀掉运用了,仍是运用溃散了。

苹果后台溃散日志的仓库尽管各不相同,但都涉及到数据库操作,所以咱们猜想,这类溃散和后台操作数据库有关。

溃散的原因:

异常码 0xdead10cc,意味着运用程序由于在后台操作体系资源(而非App沙盒内资源)而被 iOS 体系停止

咱们的运用包括一个ShareExtensionApp,为了便利主App和ShareExtensionApp同享数据,咱们把数据库默认寄存运用的同享容器(containerURLForSecurityApplicationGroupIdentifier)中,这便是问题的关键所在

咱们打印并调查一下,主App沙盒途径和同享容器途径区别:

沙盒目录(NSDocumentDirectory):

/var/mobile/Containers/Data/Application/A4B74E98-9B7D-4DA0-BA15-DFE03AA580E1/Documents/test.db

同享目录(containerURLForSecurityApplicationGroupIdentifier):
/private/var/mobile/Containers/Shared/AppGroup/806B3545-5ECE-46FF-91E0-C138449A684E/test.db

可以看到,同享目录是”private”开头的私有体系目录,并不是主App的沙盒子目录。

iOS文件的锁机制对在同享区域的文件有更严厉的要求。当iOS准备挂起一个运用的时分,体系会查看这个运用是否正在运用一些或许被其他进程运用的文件(即存在对非沙盒文件的锁),如果有,iOS就会直接停止这个运用

咱们的运用退到后台后,在被挂起前,如果仍在进行数据库操作,拜访体系private目录下的文件,体系就杀死了咱们的运用,触发0xdead10cc状况码。

怎么重现溃散:

偶现的bug最让人头疼的便是怎么复现,即便有计划修正,也不确定是否真的修正了。所以,重现溃散至关重要,无法复现,那就创造条件让它复现!

既然咱们怀疑是退到后台后,进行数据库操作导致的溃散。那咱们开发就可以通过写临时代码的方法做暴力测试,退到后台后张狂拜访和修正数据,看会不会溃散。

通过咱们的测试,复现了溃散,且溃散过错类型和苹果后台的一致,验证了咱们的猜想。
需要留意的是,Debug模式下,过错码是3735883980,网上查了下材料,该值就对应Release模式下的0xdead10cc过错码。

Exception Type: EXC_CRASH (SIGKILL)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Termination Reason: RUNNINGBOARD 3735883980

解决计划:

起初,咱们想的计划是,运用退到后台前,暂停数据库操作,回到前台后康复操作。但这好像并不容易,你需要保留现场和状况,怎么康复是一个检测。

咱们最终选用的计划是,把主App的数据库文件挪到App沙盒目录中寄存,然后在适宜的机遇同步一份到ShareExtensionApp的同享目录。这样,就不存在退到后台依然拜访private目录加锁的问题了。

怎么同步:删除同享目录的.db文件,复制App沙盒目录的.db文件到同享目录。

同步机遇:这个结合自己的事务场景制定即可,比方 App启动时、App回到前台时。尽量防止App处于后台时做同步操作。

总归,iOS体系对于private目录下的文件会更灵敏,文件的操作尽量在自己的沙盒目录下进行(比方先把文件从private目录复制到沙盒目录),减少对private目录文件的拜访和修正,防止各种异常情况产生

参考文献
怎么防止运用溃散
0xdead10cc问题调研
Crash in iOS 15 EXC_CRASH (SIGKILL) without reason on TestFlight