Xcode 4.2/iOS 5下控制台没有异常堆栈信息?

48
在Xcode 3.x和iOS 4下,如果模拟器中发生未处理的异常,控制台输出会产生一个异常堆栈跟踪(类似于Java)。但是,在Xcode 4.2下运行相同的应用程序代码时,当我引发未处理的异常时,堆栈跟踪不会发生。(我确实找到了如何设置异常断点,但这并没有在控制台中产生回溯。)这只是我需要在Xcode中进行的设置,还是Xcode 4/iOS 5的“特性”?有没有办法恢复这个功能?
更新:不幸的是,添加uncaughtExceptionHandler无效。以下是处理程序:
void uncaughtExceptionHandler(NSException *exception) {
    NSLog(@"uncaughtExceptionHnadler -- Exception %@", [exception description]);
    // Because iOS 5 doesn't provide a traceback, provide one here
    NSLog(@"Stack trace: %@", [exception callStackSymbols]);
    // Let Flurry look at the error
    [FlurryAPI logError:@"Uncaught" message:@"Crash!" exception:exception];
}                                               

(原来已经存在,为了做Flurry的事情,我只是添加了堆栈跟踪。)
这里是启用它的地方(在处理程序声明的几行下面):
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    // Enable uncaught exception handler to dump stack and let Flurry log the exception
    NSUncaughtExceptionHandler* hdlr = NSGetUncaughtExceptionHandler();
    NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
    NSUncaughtExceptionHandler* newHdlr = NSGetUncaughtExceptionHandler();
    
    // TODO: Test
    NSException* ex = [NSException exceptionWithName:@"AssertionFailure" reason:@"Test" userInfo:nil]; 
    @throw ex; 

我设置了断点以便检查两个检索到的处理程序值。第一个值为nil,第二个值是一个看似有效的地址。但是当测试异常被抛出时,在iOS 5模拟器中处理程序从未控制。(尽管在运行iOS 4.2模拟器时它确实被控制。)
在iPhone上设置NSExceptionHandlingMask显然是不可能的。先决条件ExceptionHandling.framework不可用。
更新2:
这样可以:
int main(int argc, char *argv[]) {
    
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    int retVal = -1;
    @try {
        retVal = UIApplicationMain(argc, argv, nil, nil);
    }
    @catch (NSException* exception) {
        NSLog(@"Uncaught exception: %@", exception.description);
        NSLog(@"Stack trace: %@", [exception callStackSymbols]);
    }
    [pool release];
    return retVal;
}

很棒,很高兴问题已经解决 :-) 或许你可以将其作为回答添加(不仅仅是在问题描述中)。 - Yahia
如果没有其他人提出使uncaughtExceptionHandler工作的修复程序,我可能会这样做。 - Hot Licks
仍在等待某种解释,说明为什么默认转储不再起作用和/或为什么(更为严重的是)'uncaughtExceptionHandler'不起作用。 - Hot Licks
你所描述的问题似乎只影响模拟器... 在真实设备上它能够正常工作... - Yahia
1
很好,你标记其他问题(询问不同的事情)作为重复问题的借口,以便将其指回这个问题,从而使你的问题获得更多的关注度和更多的积分。恭喜你发现了如何操纵系统,但是由于这个原因,我的问题--尚未得到答复--被关闭为重复问题,使stackoverflow对每个人都变得不那么有用。 - nirvana
3个回答

36

这个有效:

int main(int argc, char *argv[]) {

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    int retVal = -1;
    @try {
        retVal = UIApplicationMain(argc, argv, nil, nil);
    }
    @catch (NSException* exception) {
        NSLog(@"Uncaught exception: %@", exception.description);
        NSLog(@"Stack trace: %@", [exception callStackSymbols]);
    }
    [pool release];
    return retVal;
}

针对ARC:

int main(int argc, char *argv[]) {

    int retVal = -1;
    @autoreleasepool {
        @try {
            retVal = UIApplicationMain(argc, argv, nil, nil);
        }
        @catch (NSException* exception) {
            NSLog(@"Uncaught exception: %@", exception.description);
            NSLog(@"Stack trace: %@", [exception callStackSymbols]);
        }
    }
    return retVal;
}

仍在等待某种解释,说明为什么默认转储(dump)不再有效和/或为什么(更严重的是)未捕获的异常处理程序(uncaughtExceptionHandler)无法工作。但是,显然这个问题只影响模拟器(emulator)。

更新:

有人指出,如果您转到“Product -> Scheme -> Edit Scheme”,选择“Run (Debug)”,选择“Diagnostics”选项卡,然后单击“Log Exceptions”,这将恢复缺失的Xcode默认异常日志记录功能,可能(我还没有尝试)消除了上述hack的需要。


1
如果您正在使用ARC,请将autorelease alloc/release更改为@autoreleasepool {...} - Hot Licks
2
可能只是忘记了,但我必须为返回值retVal = UIApplicationMain(argc, argv, nil, NSStringFromClass([YourAppDelegate class]));做这个。 - Jay Q.
3
完全不需要做这件事。您只需创建异常断点即可,参见http://blog.manbolo.com/2012/01/23/xcode-tips-1-break-on-exceptions。 - Kerni
只需启用“僵尸对象”,就解决了让我苦恼一整天的问题! - RyJ
这真的是一个巨大的帮助!让我实际找到了问题所在。谢谢 @HotLicks - jsetting32
非常感谢,我简直不敢相信我得为这个问题进行研究,真是难以置信,我已经浪费了好几个小时。 - Volkan Ozyilmaz

2

这是一个已知的问题...有解决方法,请参考这里这里

另一个选择可能是

defaults write NSGlobalDomain NSExceptionHandlingMask 63

虽然它通常用于OSX,但在使用仿真器时可能会有所帮助-不过很遗憾我现在无法尝试:-(


就我个人而言,“defaults write NSGlobalDomain NSExceptionHandlingMask 63”对我没有起作用。 - Tylerc230
此外,这在iOS SDK中不可用。 - memmons

1

我曾经遇到过同样的问题,重新打开“编译为Thumb”选项对我有用。注意:出于明显的原因,我只在调试配置中重新打开了它。


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