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

来源:互联网 发布:淘宝平面男模特动作 编辑:程序博客网 时间:2024/06/06 03:56
没有任何crash发生,在我们来看是最好工作愉快您的应用程序,一切都很好!然后突然 -  - 崩溃 aaargh (提示悲伤小提琴。
首先要做的是:不要惊慌!
修复崩溃并不需要很难如果吓坏了开始随意改变事情,你很可能使局势恶化;你如果期望说出正确的咒语,希望错误会奇迹般地消失,你在做梦相反,你需要采取有条不紊的方法并学习如何通过自己的方式找崩溃的原因

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

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

iOS指南系列:如何解决奔溃问题-关于内存访问

iOS指南系列:如何解决奔溃问题-关于内存访问续

iOS指南系列:如何解决奔溃问题-关于内存访问续


入门
下载示例项目example project正如看到,这是一个错误的程序当您打开在Xcode项目,它显示了至少8编译器的警告,这始终是头痛的问题顺便说一下,我们对于本教程使用的Xcode4.3虽然4.2版本应该工作一样
注:要按照本教程需要iOS5模拟器运行的应用程序如果您的设备上运行的应用程序仍然会得到崩溃但他们可能不会出现相同的顺序
让我们在模拟器上运行应用程序,看看会发生什么


基本上有两种类型SIGABRT信号(也称为EXC_CRASHEXC_BAD_ACCESS也可以显示产生SIGBUSSIGSEGV的名称可能发生崩溃
SIGABRT信号一个相当不错一个因为它是一个可控制的崩溃终止的目的,因为系统识别应用程序的应用程序的东西不应该
EXC_BAD_ACCESS另一方面调试增加了很多困难,因为它只会发生钻进了一个损坏的状态时,应用程序,通常是由于内存管理问题
幸运的是,这个崩溃许多人还没来一个SIGABRT发出SIGABRT总是一个错误消息,你可以看到Xcode的调试输出窗格(右下窗口角落 (如果你没有看到调试输出“窗格中点击中间的图标您的Xcode窗口右上角显示调试视图图标如果调试输出窗格仍然是不可见的你可能挖掘调试顶部中间的图标 - 搜索字段旁边图标在这种情况下,它说是这样的:

我们就看最重要的一行

[UINavigationController setList:]: unrecognized selector sent to instance 0x6a33840
这里有问题的对象位于内存地址0x6a33840UINavigationController,方法setList
知道奔溃原因好的,但行动首先当然是要弄清楚在那个代码中发生此错误你需要找到源文件名称行为不端的代码所在为此,您可以使用调用栈又称堆栈跟踪回溯
一个应用程序崩溃的Xcode窗口左窗格中切换到Debug导航它显示活跃在应用程序中的线程并强调崩溃线程通常是线程1应用程序主线程,因为在那里你会做大部分工作如果您的代码使用队列后台线程那么应用程序可能会崩溃其他线程


The call stack. It doesn't show everything yet.

目前,Xcode的突出问题的根源main.m main()函数这并不能告诉你非常多,所以你必须得更深一些
看到更多调用堆栈拖动滑块底部调试导航的最右边崩溃时刻,将显示完整调用堆栈

The expanded call stack.


构造出调用顺序图:

How a call stack works.



所有这些函数方法调用堆栈中除了为main()是灰色的这是因为他们内置在iOS框架没有为他们提供源代码
源代码唯一这个堆栈跟踪main.m,所以这是什么Xcode源代码编辑器中显示,尽管它不是一个真正崩溃真正来源往往混淆新的开发在一分钟内我会告诉你如何做,看到它的真实意义
尝试一下,单击堆栈跟踪其他项目任何一个会看到一堆汇编代码可能不会给你太大的意义

If there is no source code, Xcode shows assembly.

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


异常断点
那么,你如何找到应用程序崩溃的代码吗?好了,只要像这样的堆栈跟踪异常被抛出的应用程序 你可以告诉,因为调用堆栈中的职能之一被命名为objc_exception_rethrow)。
发生异常捕获程序时,做一些不应该现在看到这个异常后果应用程序做了错事已引发异常Xcode中显示您的结果理想的情况下,希望看到的正是这种异常抛出
幸运的是,你可以告诉Xcode暂停刚才那一瞬间方案使用一个异常断点断点是调试工具,停在一个特定的时刻,根据计划本教程第二部分你会看到他们,但现在你会使用特定断点暂停程序只是一个异常抛出


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


The Breakpoint Navigator

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

Adding the Exception Breakpoint

A new breakpoint will be added to the list:

After the Exception Breakpoint has been added


[cpp] view plaincopyprint?
  1. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions  
  2. {  
  3.     MainViewController *viewController = (MainViewController *)self.window.rootViewController;  
  4.     viewController.list = [NSArray arrayWithObjects:@"One", @"Two"];  
  5.     return YES;  
  6. }  



这样更好了源代码编辑器现在出现了源代码行 - 没有更多的讨厌汇编代码的东西 在左边调用堆栈您可能需要通过调试导航切换调用堆栈取决于你如何在 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:

The storyboard has a navigation controller.

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.

The different parts of the 'Unrecognized selector' error message.

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呢?请听下回分解




How a call stack works.

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:

If there is no source code, Xcode shows assembly.

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