Xcode 9 / iOS 11 "CALayer bounds contains NaN: [nan 0; nan 0]" 当使用嵌套的 UINavigationController 和 UITabBarController 弹出视图控制器时

Xcode 9 / iOS 11 "CALayer bounds contains NaN: [nan 0; nan 0]" when popping view controller with nested UINavigationController and UITabBarController

我正在为 Xcode 9、Swift 4、iOS 11 和 iPhone X 更新我的申请。它似乎一路相对顺利,但每当我按下后退按钮时,我的应用程序就会崩溃。我可以毫无问题地前进 3-4 个屏幕,但第一个后退按钮总是使应用程序崩溃。它不需要模拟器 运行 作为 iPhone X.

它似乎没有深入到我的堆栈跟踪代码中,所以我认为这是我正在弹出的视图控制器的重绘阶段,但我不确定。

因为我做了很多自定义绘图,因为 UITableViews 和 UIViews 周围有自定义阴影,所以我在除以变量的所有位置设置断点,但没有命中。所以似乎不是我的代码按零计算。

*** Terminating app due to uncaught exception 'CALayerInvalidGeometry', reason: 'CALayer bounds contains NaN: [nan 0; nan 0]'
*** First throw call stack:
(
    0   CoreFoundation                      0x000000010af711cb __exceptionPreprocess + 171
    1   libobjc.A.dylib                     0x000000010a8d3f41 objc_exception_throw + 48
    2   CoreFoundation                      0x000000010afe5b95 +[NSException raise:format:] + 197
    3   QuartzCore                          0x0000000109424424 _ZN2CA5Layer10set_boundsERKNS_4RectEb + 230
    4   QuartzCore                          0x0000000109414c29 -[CALayer setBounds:] + 251
    5   UIKit                               0x0000000107267439 __27-[_UILabelLayer setBounds:]_block_invoke + 80
    6   UIKit                               0x000000010726717b -[_UILabelLayer _setFrameOrBounds:settingAction:] + 23
    7   UIKit                               0x00000001072673d8 -[_UILabelLayer setBounds:] + 155
    8   QuartzCore                          0x000000010941537c -[CALayer setFrame:] + 630
    9   UIKit                               0x0000000107267319 __26-[_UILabelLayer setFrame:]_block_invoke + 80
    10  UIKit                               0x000000010726717b -[_UILabelLayer _setFrameOrBounds:settingAction:] + 23
    11  UIKit                               0x00000001072672b8 -[_UILabelLayer setFrame:] + 155
    12  UIKit                               0x0000000106c4cf1e -[UIView(Geometry) setFrame:] + 368
    13  UIKit                               0x0000000106e4ec40 -[UILabel setFrame:] + 141
    14  UIKit                               0x0000000106fff254 -[UIButton _layoutTitleView] + 248
    15  UIKit                               0x0000000106fff3cf -[UIButton layoutSubviews] + 250
    16  UIKit                               0x0000000106c6c551 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1331
    17  QuartzCore                          0x000000010941b4ba -[CALayer layoutSublayers] + 153
    18  QuartzCore                          0x000000010941f5a9 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 401
    19  QuartzCore                          0x00000001093a81cd _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 365
    20  QuartzCore                          0x00000001093d3ae4 _ZN2CA11Transaction6commitEv + 500
    21  UIKit                               0x0000000106b97f4a _UIApplicationFlushRunLoopCATransactionIfTooLate + 167
    22  UIKit                               0x00000001074ef960 __handleEventQueueInternal + 6894
    23  CoreFoundation                      0x000000010af142b1 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
    24  CoreFoundation                      0x000000010afb3d31 __CFRunLoopDoSource0 + 81
    25  CoreFoundation                      0x000000010aef8c19 __CFRunLoopDoSources0 + 185
    26  CoreFoundation                      0x000000010aef81ff __CFRunLoopRun + 1279
    27  CoreFoundation                      0x000000010aef7a89 CFRunLoopRunSpecific + 409
    28  GraphicsServices                    0x00000001104e59c6 GSEventRunModal + 62
    29  UIKit                               0x0000000106b9dd30 UIApplicationMain + 159
    30  My Customer's Application Name      0x000000010475f087 main + 55
    31  libdyld.dylib                       0x000000010cfedd81 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

因为我在修复它时已经完成了所有输入(它总是有助于向其他人表达你的问题;-))我决定 post 我的问题和答案。

我有一个导航设置,其中标签栏嵌套在导航控制器中。我知道我们被警告过不要这样做,但是,嘿,它一直都很有效。通过外观代理设置大标题视图后如下:

    if #available(iOS 11.0, *) {
        UINavigationBar.appearance().prefersLargeTitles = true
    }

返回时屏幕开始崩溃。将其改回 false 使所有问题都消失了。

TL;DR: 在我们的例子中,这个 iOS 11 / Xcode 9 错误是由添加自定义 UILabel 的代码引起的到 UINavigationItem.titleView

此代码是使用臭名昭著的混合技术编写的,该技术覆盖了 -[UINavigationItem setTitle:] 选择器 - 在调用原始 setTitle: 方法的同时,我们的开发人员还将具有相同标题的自定义标签设置为 UINavigationItem.titleView 属性。问题是当使用 setTitle:nil 调用导航项时,空的 UILabel 被添加到具有 zero-rect 尺寸的 .titleView,这导致 UIKit 崩溃。如果 title: 参数为零,立即的快速修复是停止设置 .titleView。 long-term 修复将从应用程序中删除 swizzling。

P.S。我打开了一个雷达,请求改进此错误的错误消息:

Xcode 9: Please improve error handling: -[UILabel setFrame:] and -[CALayer setFrame:] throws unfriendly exception if given a malformed CGRect

我遇到了同样的问题,因为工具栏标题在之前的 VC 中设置为空字符串。一旦我用至少某种文本设置了所有标题,我就不再崩溃了。同样,这仅适用于 iOS 11 和 Xcode 9,在以前的版本中有效。

当我为 NavigationBar 设置指定 ViewController 时发生了这种情况,首选大标题 = true。

我用 pjapple15 的方法解决了它。我只是在前一个 ViewControllerNavigationBar 中设置了一个像空字符串 = " " 这样的标题,它工作正常。

而且我还在NavigationBar.titleView,中添加了一个SearchBar,之后我就设置了NavigationItem.title = " ".