【问题标题】:Xcode won't step over crashXcode 不会越过崩溃
【发布时间】:2014-04-10 00:38:15
【问题描述】:

因此,这种情况在许多不同的项目中已经发生过多次。当 Xcode 出现错误时,我将在 Xcode 中调试我的应用程序。看完之后,我会点击 Step Over 或 Continue ......它不会做任何事情。更准确地说,它表现得像踩踏一样,但实际上并没有去任何地方。据我所知,这可以无限期地重复。这是有问题的一个原因是它永远不会给我崩溃日志,因为它永远不会完成崩溃。我只会在应用程序崩溃且未对其进行调试时获得崩溃日志(这意味着我必须通过 Crittercism 或通过检查设备日志来获得它)。

有人以前见过这个,和/或知道为什么会这样吗?我在其他地方没有看到任何提及这一点,但它在几个项目中发生在我身上。

例如,在一个项目中,我们使用了 SocketRocket,并且每隔一段时间(出于未知原因)它会在 SRWebSocket.m 中以以下方法崩溃:

- (void)main;
{
    @autoreleasepool {
        _runLoop = [NSRunLoop currentRunLoop];
        dispatch_group_leave(_waitGroup);

        NSTimer *timer = [[NSTimer alloc] initWithFireDate:[NSDate distantFuture] interval:0.0 target:nil selector:nil userInfo:nil repeats:NO];
        [_runLoop addTimer:timer forMode:NSDefaultRunLoopMode];

        int i = 0;

        while ([_runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]) {
            NSLog(@"_runLoop %i %@", i++, [NSDate date]);
        }
        assert(NO);
    }
}

它在while 行崩溃。 (顺便说一句,我添加了 NSLog 行)。当我点击 Continue 或 Step Over 时,行指示器会短暂闪烁,然后再次出现在同一行上。请注意,它不会继续到 NSLog 行,并且根本没有任何内容写入控制台。我目前仍在尝试让它再次崩溃(这个特殊的崩溃是相当不可预测的),但如果我没记错的话,行指示器显示EXC_BAD_ACCESS,可能是一个过早释放的对象。

【问题讨论】:

  • 您确定没有遗漏什么吗?可能是写到控制台的东西?
  • @ThomasW 不,这就是问题所在 - 没有任何东西写入控制台,它没有完成崩溃,它只是在那里中断并且不会继续前进。
  • 它也没有在断点处停止?也许您在异常上设置了断点?
  • @ThomasW 我不相信我会这样做,即使我这样做了,我应该仍然能够超越他们,对吧?
  • 你有没有想过在while循环中SRWebSocket崩溃的原因?也会发生崩溃......

标签: ios objective-c xcode debugging xcode5


【解决方案1】:

您错过了 Step Over 的要点。当您跨过一行时,您是在说执行当前行并转到下一个可见行,而不管当前行是否调用另一个过程。

如果代码在任何时候崩溃,您将无法继续执行代码行。

【讨论】:

  • 我知道。但我相信它 应该 完成崩溃并给我堆栈跟踪等 - 我记得它是为其他崩溃完成的。但是,有时它会卡在这条线上。
  • 您能否将受影响的行和您收到的任何消息添加到您的问题中?没有它,很难说具体发生了什么。
  • 所以你说“EXC_BAD_ACCESS,可能是一个过早释放的对象。”那是你的错误,也是原因。同样,一旦发生崩溃,将不会执行任何其他操作。
  • 请注意NSArray *a = [[NSArray alloc] init]; [a objectAtIndex:5]; 在运行时实际上会崩溃并记录预期的堆栈跟踪。当我点击继续时,程序确实继续:它完成崩溃并终止。与int *b = NULL; NSLog(@"b %i", *b); 相比,它在运行时会在第二条语句上中断,不会记录堆栈跟踪,并且无论我多久按一次继续,都会在该语句上无限循环。我知道程序在崩溃后无法继续正常执行,但至少我应该能够获得记录的堆栈跟踪。
【解决方案2】:

ObjC 超出范围错误将导致抛出 ObjC 异常,如果未捕获,该异常最终会中止。中止实际上只是引发了一个 BSD 信号(SIGKILL)。这对调试器来说很容易传递给进程,因此它可以自然地死掉。

EXC_BAD_ACCESS 和 EXC_BAD_INSTRUCTION 是有趣的例外,因为它们首先出现在操作系统的 Mach 端。为了正确传播,如果有处理程序,它们应该作为 Mach 异常本地处理,如果没有,它们应该传递给某个系统处理程序,这会将它们变成等效的 BSD 异常(SIGSEGV),然后将其传递给BSD 信号处理程序,这最终会导致您的程序退出。

提供给调试器的内核接口中存在一个长期存在的错误,这使得调试器无法从外部正确地影响这个小小的舞蹈。所以如果你得到一个 EXC_BAD_ACCESS,你几乎就被困在那里了。在大多数情况下,这并不重要,你的程序无论如何都会转身而死。通过观察它,你不会真正了解你的崩溃。

仅当您已安装并想要调试 SIGSEGV 处理程序时才重要。这在 MacOS X 上已经困难了十年或更长时间。幸运的是,实际上只有极少数人需要这样做......

【讨论】:

  • 谢谢;这听起来像是一个合理的解释。不过,像往常一样记录堆栈跟踪(等)会很方便 - 知道是否可以强制记录异常?
  • 基于语言的异常需要特殊处理,因为它们不会导致程序终止,直到异常传播到最外层的处理程序。所以异常的来源就丢失了。 EXC_BAD_ACCESS 等情况并非如此。在这种情况下,如果您的程序在调试器中运行,它将在异常点停止,并且您可以使用“bt”和其他调试器命令来记录异常,因为您将在异常点停止。否则会生成崩溃日志。
【解决方案3】:

添加到以前的答案;在调试和 EXC_BAD_ACCESS 时,有时有助于在您的方案中“启用僵尸对象”。如果您正在访问已被释放的对象,僵尸对象会告诉您不应该尝试调用的对象以及您尝试调用的方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-11
    • 2012-04-13
    • 1970-01-01
    • 1970-01-01
    • 2016-03-04
    • 2019-03-28
    相关资源
    最近更新 更多