这个错误是什么原因造成的?"CALayer位置包含NaN:[240 nan]"

49

每当我旋转一个包含UITableView的屏幕时,我都会看到这种情况发生。我发现它发生在UIViewController类的willRotate方法和didRotate方法之间。我的同事们也在其他地方看到过它,通常都与旋转有关。直到最近才开始出现这种情况,我们还不知道该如何处理它(谷歌搜索没有准确的错误信息)。是否有其他人遇到过这种情况并知道如何解决?

7个回答

40

决定将此评论作为答案发布,因为我认为这是一个非常出色的答案 :)

哈!我也遇到了NaN计算(div0)。关键的调试工具:输出问题的消息是由NSLog()输出的,所以在NSLog()上设置断点,观察操作系统在那个时候正在做什么。对我而言,是myUISlider.value = NaN。

设置断点:

XCode 3.x

  • CMD-SHIFT-Y(调试窗口)。
  • 断点按钮。
  • “双击符号”
  • 输入“NSLog”(不要引号)。

XCode 4.x

  • CMD-6(断点导航器)。
  • “+”添加断点(左下方)。
  • 选择ADD SYMBOLIC BREAKPOINT。
  • 符号:NSLog
  • 确认:完成。

XCode 5.x - 7.1(至少) (与4.x相同,只是断点导航器现在是CMD-7。)

运行应用程序,在NSLog上中断,检查堆栈跟踪。


1
这是实际上涉及到此异常时最重要的答案。需要注意的是,此异常可能会从使用CALayer的组件中引发,而我们API用户并不知道它们的存在(感谢封装)。 - Pacu
1
很好,为调试方法加一分。 - Alexander Tkachenko
1
@Caio:如果你没有得到断点,(a)验证你的断点是否停在NSLog()上(测试记录日志),(b)或许你得到的错误不是由NSLog()输出的;看看能否在其他地方中断。我的回答关键在于:因为我找不到要断点的代码,所以我在输出消息的部分中断了。也许从你的堆栈跟踪中找iOS异常处理代码,并尝试在那里中断。 - Olie
1
@Olie 终于找到了到底发生了什么。除以零的操作是由内部UIScrollView方法执行的,这就是为什么断点没有在NSLog上中断的原因。有时一个约束可能为0。 - Caio
3
在 Xcode 8 中,我遇到了一个 CALayer position contains NaN 错误导致程序终止并抛出了一个 NSException 异常。通过设置异常断点:All Exceptions,我得到了堆栈跟踪信息。(符号断点:NSLog 并没有提供相应信息。) - Warren Whipple
显示剩余3条评论

28

我找到了问题所在。

当你重置tableview的框架时,它会为表格中的每一行调用委托方法tableView:heightForRowAtIndexPath:,这样它就可以在需要时重新计算内容大小。此时,我们进行一些特殊处理来返回高度,由于代码中存在一些错误的假设,我们错误地返回了NaN,因为变量被假定永远不为零而进行了除以零的操作。确保我们在这里不会除以零就可以解决问题。


我遇到了相同的错误(位置和边界都包含NaN,通常是成对出现的消息。)只有在我的视图显示之前才会出现。没有旋转、表格或花哨的计算。一个简单的深灰色视图,带有标签“处理中…”和进度指示器。还有其他人对此有什么想法吗? - Olie
1
在你的viewDidLoad/viewWillAppear方法中设置一些断点,确保你没有意外地除以零。 - Kevlar
可能与此有关,但我曾经在Mavericks OSX 10.9中更加一致地看到了这个崩溃,但在OSX 10.9.2更新后再也没有看到过。 - Sean Larkin
这让我对我的项目问题有了更清晰的认识...由于我正在使用单独的storyboard,我要呈现的viewController具有一个tableView,而我没有发送正确的值。 - Michael Lau

16

在启用Xcode的“异常中断”之后,我花了一天时间尝试查找导致同样问题的代码,并在几分钟内解决了它。查看此教程以了解如何启用它。


1
你能否包含一个页面内容的简短摘要?这样,未来阅读此帖子的读者可以快速轻松地获取他们正在寻找的信息。 - gobernador
3
@gobernador 好的,我会这么做,因为它刚刚帮了我一个大忙!要找到您的应用程序停止运行的确切行,请转到 xcode 左侧的断点标签页,单击 "+",添加一个新的“异常断点”,并将设置保留为默认设置。点击完成,重新运行您的应用程序即可。 - spamoom

13

我曾经遇到过这个问题,当时我假设:

tableView:heightForHeaderInSection: 返回的是一个 NSInteger,但实际上它返回的是一个 CGFloat...

修改为:

-(NSInteger)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
< p > 到

-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section

问题已经解决。

编辑:

我在某个时刻学会了如何理解C语言以下的计算机工作原理,因此我想分享一下...(我将使用x86_64的寄存器名称,因为我对这些最熟悉,ARM会有些不同但类似)

int f(){
          float someFloat=5.0f;
          return someFloat;
       }

someFloat的值转换为整数类型,然后将其复制到特定寄存器:%rax,然后调用返回指令。

float f(){
          float someFloat=5.0f;
          return someFloat;
       }

将导致将someFloat的值从其当前位置复制到特定寄存器:%xmm0,然后调用返回指令。

因此,如果您使用错误的原型,调用代码将期望值出现在错误的位置,最终会返回垃圾值。


3
这个错误也让我浪费了很长时间。
最后,我发现我的同事写了这样的内容:
UIEdgeInsets a;
a.left = (...some calculation);
button.imageEdgeInsets = a;

我将这些代码重写并修复了问题,如下所示:
UIEdgeInsets a;
a.left = (...some calculation);
a.top = 0;
a.bottom = 0;
a.right = 0;
button.imageEdgeInsets = a;

有些UIEdgeInsets的值没有被正确初始化,有时会变成NaN,导致应用崩溃。
更一般地说,您应该检查所有C风格结构体的值是否被正确初始化。


2

还有另一种复现问题的方法:在一个太小的矩形上使用insetBy(dx:dy:)

enter image description here


-1
你可以尝试使用 yourTableview?.bounces = false。这对我有效。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接