您的位置:首页 > 移动开发 > IOS开发

iOS指南系列:如何解决奔溃问题

2012-11-07 16:54 579 查看
没有任何crash发生,在我们来看是最好的:你工作愉快,对您的应用程序,一切都很好!然后突然 - 噗! - 崩溃。 aaargh!! (提示悲伤的小提琴。)

首先要做的是:不要惊慌!

修复崩溃并不需要是很难的。如果你吓坏了,并开始随意改变事情,你很可能使局势恶化;你如果期望只说出正确的咒语,希望错误会奇迹般地消失,你在做梦。相反,你需要采取有条不紊的方法,并学习如何通过自己的方式找崩溃的原因。

首先是为了找出确切位置在您的代码崩溃发生在哪个文件,哪一行。 Xcode调试将帮助你,但你需要了解如何使物尽其用,这正是本教程将告诉你!

入门

下载示例项目example project正如你看到的,这是一个错误的程序!当您打开在Xcode的项目,它显示了至少8个编译器的警告,这始终是头痛的问题。顺便说一下,我们对于本教程使用的Xcode4.3,虽然4.2版本应该工作一样。

注:要按照本教程的需要iOS5模拟器上运行的应用程序。如果您的设备上运行的应用程序,你仍然会得到崩溃,但他们可能不会出现相同的顺序。

让我们在模拟器上运行的应用程序,看看会发生什么。

基本上有两种类型:SIGABRT信号(也称为EXC_CRASH)和EXC_BAD_ACCESS(这也可以显示下产生SIGBUS或SIGSEGV的名称)可能发生的崩溃。

SIGABRT信号是有一个相当不错的一个,因为它是一个可控制的崩溃。终止的目的,因为系统识别应用程序的应用程序做的东西是不应该的。

EXC_BAD_ACCESS,另一方面,给调试增加了很多困难,因为它只会发生钻进了一个损坏的状态时,应用程序,通常是由于内存管理的问题。

幸运的是,这个崩溃(许多人还没来)是一个SIGABRT。发出SIGABRT总是一个错误消息,你可以看到在Xcode的调试输出窗格(右下窗口的角落)。 (如果你没有看到调试输出“窗格中,点击中间的图标在您的Xcode窗口右上角显示调试区的视图图标节。如果调试输出窗格仍然是不可见的,你可能挖掘在调试区的顶部中间的图标 - 搜索字段旁边的图标)。在这种情况下,它说是这样的:

我们就看最重要的一行

[UINavigationController setList:]: unrecognized selector sent to instance 0x6a33840
在这里,有问题的对象是位于内存地址0x6a33840UINavigationController,方法是setList:。

知道奔溃的原因是好的,但你的行动首先当然是要弄清楚在那个代码中发生此错误。你需要找到源文件的名称和行为不端的代码所在行数。为此,您可以使用调用栈(又称堆栈跟踪或回溯)。

当一个应用程序崩溃的Xcode窗口的左窗格中切换到Debug导航。它显示是活跃在应用程序中的线程,并强调崩溃的线程。通常是线程1,应用程序的主线程,因为在那里,你会做你的大部分工作。如果您的代码使用队列或后台线程,那么应用程序可能会崩溃在其他线程。





目前,Xcode的突出问题的根源在main.m main()函数。这并不能告诉你非常多,所以你必须挖得更深一些。

看到更多的调用堆栈,拖动滑块在底部的调试导航的最右边。在崩溃的时刻,将显示完整的调用堆栈:





构造出调用顺序图:





所有这些函数和方法调用堆栈中,除了为main(),是灰色的。这是因为他们从内置在iOS框架。有没有为他们提供的源代码。

你源代码是唯一在这个堆栈跟踪main.m,所以这是什么Xcode的源代码编辑器中显示,尽管它不是一个真正的崩溃的真正来源。这往往混淆了新的开发,但在一分钟内,我会告诉你如何做,看到它的真实意义。

尝试一下,单击“从堆栈跟踪的其他项目中的任何一个,你会看到一堆汇编代码可能不会给你太大的意义:





Oh, if only we had the source code for that! :-]

异常断点

那么,你如何找到应用程序崩溃的代码行吗?好了,只要你像这样的堆栈跟踪,异常被抛出的应用程序。 (你可以告诉,因为调用堆栈中的职能之一,被命名为objc_exception_rethrow)。

发生异常捕获程序时,做一些不应该做的。你现在看到的是这个异常的后果:应用程序做了错事,已引发异常,Xcode中显示您的结果。理想的情况下,你希望看到的正是这种异常被抛出。

幸运的是,你可以告诉Xcode暂停在刚才那一瞬间的方案,使用一个异常断点。断点是调试工具,停在一个特定的时刻,根据你的计划。在本教程的第二部分,你会看到他们,但现在你会使用特定的断点将暂停程序,只是前一个异常被抛出。

总结来说,下面的步骤就是启用first-chance exception当第一次 错误抛出就断下。。。





At the bottom is a small + button. Click this and select Add Exception Breakpoint:





A new breakpoint will be added to the list:





[cpp] view
plaincopy

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

{

MainViewController *viewController = (MainViewController *)self.window.rootViewController;

viewController.list = [NSArray arrayWithObjects:@"One", @"Two"];

return YES;

}

这样更好了!源代码编辑器现在出现了,从源代码行 - 没有更多的讨厌汇编代码的东西 ,在左边的调用堆栈(您可能需要通过调试导航切换到调用堆栈,这取决于你如何在 Xcode中设置上)看起来也不同。

显然,罪魁祸首就是这行:在AppDelegate中的应用didFinishLaunchingWithOptions:方法:

viewController.list=[NSArray的arrayWithObjects:“一”,“二”;

采取再看看该错误消息:

[UINavigationController的setList:]:无法识别的选择发送到实例0x6d4ed20

在代码中,“viewController.list=东西”呼吁setList:幕后,因为“清单”是上MainViewController类的属性。然而,根据错误信息的ViewController变量不点到MainViewController对象,而是一个UINavigationController - 当然,UINavigationController的没有“名单”属性!这样的事情在这里混了。

Open the Storyboard file to see what the window’s rootViewController property actually points to:





Ah ha! The storyboard’s initial view controller is a Navigation Controller. That explains why window.rootViewController is a UINavigationController object instead of the MainViewController that you’d expect. To fix this, replace application:didFinishLaunchingWithOptions: with
the following:

通过上图,storyboard的第一个就是 root,是navigationcontroller,接下来的第一个scenes才是mainviewcontroller

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UINavigationController *navController = (UINavigationController *)self.window.rootViewController;
MainViewController *viewController = (MainViewController *)navController.topViewController;
viewController.list = [NSArray arrayWithObjects:@"One", @"Two"];
return YES;
}
First you get a reference to the UINavigationController from self.window.rootViewController, and once you have that you can get the pointer to the MainViewController by asking the navigation controller for its topViewController. Now the viewController variable
should point to the proper object.

Note: Whenever you get a “unrecognized selector sent to instance XXX” error,
check that the object is of the right type and that it actually has a method with that name. Often you’ll find that you’re calling a method on a different object than you thought, because a pointer variable may not contain the right value.





Another common reason for this error is a misspelling of the method name. You’ll see an example of this in a bit.

两个问题:

1. 指针是错的

2.方法/属性真的是没有的(包括拼写错误)

好,我们先看了第一个问题,修改后看看,继续crash,下回分析怎么看memory 问题,是不是类似windows 一样,打开heapopton呢?请听下回分解





All of these functions and methods in the call stack, except for main(), are
grayed out. That’s because they come from the built-in iOS frameworks. There is no source code available for them.

The only thing in this stacktrace that you have source code for is main.m, so
that’s what the Xcode source editor shows, even though it’s not really the true source of the crash. This often confuses new developers, but in a minute I will show you how to make sense of it.

For fun, click on any one of the other items from the stacktrace and you’ll see a bunch of assembly code which might not make much sense to you:





当我们有源代码的时候就可以看到代码啦。。。。

转自:http://blog.csdn.net/gnicky/article/details/7459238
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: