为什么我在 iPad 上出现 NS 范围异常崩溃?

问题描述

我在 Firebase 上收到了一定数量的崩溃报告,所有这些都发生在 iPad 上。

Fatal Exception: NSRangeException
*** -[__NSArrayM objectAtIndex:]: index 5 beyond bounds [0 .. 4]
_CFDataInit


Fatal Exception: NSRangeException
0  CoreFoundation                 0x1ae9139d8 __exceptionPreprocess
1  libobjc.A.dylib                0x1c2c7cb54 objc_exception_throw
2  CoreFoundation                 0x1ae97dd98 -[__NSCFString characteratIndex:].cold.1
3  CoreFoundation                 0x1ae7fcb84 _CFDataInit
4  UIKitCore                      0x1b09d6630 -[UITabBarController _viewControllerForTabBarItem:]
5  UIKitCore                      0x1b09d6690 -[UITabBarController _tabBarItemClicked:]

有没有办法找出并解决这个问题?

解决方法

简短的回答是:Apple 会在某些情况下添加额外的标签栏项目。该额外的标签栏项目位于标签栏右侧的某处。它是不可见的,但如果您或您的用户不小心点击了它,则会触发超出范围的错误。

一个简单的解决方案是在适当的时候运行以下代码。

        // If you started your app project with Apple's Tabbed App template,that is your root view controller. 
        guard let rootViewController = UIApplication.shared.windows.first(where: { $0.isKeyWindow })?.rootViewController as? UITabBarController,let items = rootViewController.tabBar.items else {return}
        for item in items {
            //Find the tab bar item that has no title,which means it is added by Appple automatically
            guard item.title == nil else {continue}
            //Disable it so that it won't trigger a _tabBarItemClicked event
            item.isEnabled = false
        } 

我是如何发现这次崩溃发生的原因的?

明显的提示是崩溃报告中的 _tabBarItemClicked。它导致索引为 5。但我的应用程序在主故事板中只绘制了五个标签栏项目。然后我使用 XCode 的视图调试器来检查视图层次结构。它确实有 6 个酒吧项目。

我做了一些额外的挖掘,并弄清楚了为什么要添加额外的栏项目。这是因为我有一个启动广告,当应用程序启动时,它涵盖了应用程序的完整视图。当我创建该视图时,Apple 认为我的选项卡视图栏有 5 个以上的项目并自动添加了一个“更多”项目。

为什么我不改变启动广告的呈现方式?

我想如果我使用视图控制器而不是选项卡视图控制器作为根视图,Apple 可能不会添加额外的栏项。但是,我必须在应用程序的整个生命周期内将选项卡视图控制器嵌入到视图控制器中。我认为,当前的解决方案更安全、更高效。当然,未来切换到 Swift UI 和协议会避免很多这样的潜在问题。