天天看点

我的 App Crashed, 怎么办? – Part 1

Thanks for visiting!

如题

❤️情美美哒工作:当你工作愉快地在你的应用程序,一切都很好,然后突然 - 噗! - 它崩溃。 Fuck! (竟然如此忧伤)。

请不要忧伤:镇静+淡定

你可能会定位崩溃位置,也可能期望这个Crash奇迹般的消失(那是不可能的了!!!),然而我们需要采取系统的方法,查到Crash的原因,彻底查出Crash的准确位置:Xcode会帮助我们,需要我们充分理解,xcode的伟大功能。

首先

下载事例Demo。正如你所看到的,这是错误的程序!当您在Xcode中打开项目,这表明至少有八个编译器警告,这始终是一有风吹草动领先。顺便说一句,我们使用本教程的Xcode4.3,但4.2版本应该工作一样好。

注意:要按照本教程中,应用程序必须要在iOS 5的模拟器上运行。如果您的设备上运行的应用程序,你还是会得到崩溃,但他们可能不会出现在同一个顺序。

我的 App Crashed, 怎么办? – Part 1

咳咳,他Crash了

基本上有两种可能发生的Crash:

  • SIGABRT (也称为EXC_CRASH)一般是过度release 或者 发送 unrecogized selector导致,SIGABRT是一个可以操控的Crash
  • EXC_BAD_ACCESS 是访问已被释放的内存导致,EXC_BAD_ACCESS,很多难以调试,通常是由于内存管理问题。

Crash表象

当一个应用程序崩溃,Xcode的窗口的左侧窗格中切换到调试导航器。这表示活跃在应用程序的线程,并强调崩溃的线程。通常,这将是线程1,应用程序的主线程,因为这是在那里你会做大部分工作。如果你的代码使用队列或后台线程,然后应用程序可以在其他线程崩溃也是如此。

我的 App Crashed, 怎么办? – Part 1

  高版本的xcode不像以前,现在大部分可以定位到错误的方法体,如上图!目前也有很多情况,Xcode中突出了main()函数中main.m文件作为问题的根源。这是不是告诉你非常多,所以你必须挖得更深一些。

  要了解更多的调用堆栈,点击在调试导航仪一路到右侧底部。这将显示在崩溃的那一刻完全调用堆栈:

  

我的 App Crashed, 怎么办? – Part 1

在这里完全关闭如上图!

每个从该列表中的项目是一个函数或从应用程序或从iOS框架之一的方法。调用堆栈显示你什么是函数或方法是目前活跃在该应用程序。调试器已暂停在该应用程序。

在底部的功能,启动(),被称为第一。某处在其执行它称它上面的功能,主要的()。这是应用程序的起始点,并且它总是会在底部附近。主()又叫做UIApplicationMain()。这是灰色箭头(在突出显示的行上在Xcode右侧窗格中的开始),指向在编辑器窗口就行了。

进一步往上走栈,UIApplicationMain()调用_run方法的UIApplication对象,其中要求CFRunLoopRunInMode(),它被称为CFRunLoopRunSpecific(),等等,一路攀升到__pthread_kill。

所有这些函数和方法的调用堆栈,除了主(),显示为灰色。这是因为它们来自内置在IOS框架。没有源代码,为他们提供。

在这个堆栈跟踪,你有源代码的唯一的事情就是main.m文件,所以这就是Xcode的源代码编辑器显示,即使它不是真正的死机的真正来源。这往往混淆了新的开发人员,但在一分钟内,我会告诉你如何理解它。

为了好玩,请单击从堆栈跟踪的其他项目中的任何一个,你会看到一堆汇编代码可能没有太大的意义给你:

我的 App Crashed, 怎么办? – Part 1

只要我们有了源代码那就可以调试了

异常断点

那么,你如何找到,使得应用程序崩溃的代码行?那么,当你得到这样的堆栈跟踪,异常被抛出的应用程序。 (你可以告诉,因为在调用堆栈中的功能之一被命名为objc_exception_rethrow。)

当程序被捉住做一些不应该做的异常情况。你看现在是什么异常的后果:应用程序做错了什么,除了已经被抛出,和Xcode说明你的结果。理想情况下,你会想看看究竟在何处该异常被抛出。

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

要设置异常断点,我们必须切换到断点导航:

我的 App Crashed, 怎么办? – Part 1

在底部是一个小+按钮。单击此按钮并选择添加例外断点:

我的 App Crashed, 怎么办? – Part 1

一个新的断点被添加到列表中:

我的 App Crashed, 怎么办? – Part 1

单击完成按钮以关闭弹出窗口。请注意,现在已启用在Xcode的工具栏上的断点按钮。如果你想运行未启用任何断点应用程序,你可以简单地切换此按钮关闭。但是现在,把它打开,并再次运行应用程序。

我的 App Crashed, 怎么办? – Part 1

Oh,Good,居然定位到了出错的地方!瞬间很开心不是吗?

显然,罪魁祸首就是这条线在AppDelegate中:didFinishLaunchingWithOptions: 方法:

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

打开故事版:

我的 App Crashed, 怎么办? – Part 1

啊哈!原来,故事版的初始视图控制器是一个导航控制器。这就解释了为什么window.rootViewController是一个UINavigationController对象而不是你所期望的MainViewController。为了解决这个问题,更换申请:didFinishLaunchingWithOptions:有以下几点:

- (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;
}
           

首先,你得到一个参考的UINavigationController从self.window.rootViewController,一旦你有,你可以通过询问导航控制器,其topViewController得到的指针MainViewController。现在的viewController变量应指向正确的对象。

小贴士:

当你得到一个“无法识别的选择发送到实例XXX”的错误,检查对象是正确的类型,它实际上有与该名称的方法。通常情况下,你会发现,你呼吁比你想象的不同对象的方法,因为指针变量可能不包含正确的值。

你的第一个内存错误

这应该有固定我们的第一个问题。再次运行该应用程序。哎呀,它崩溃在同一行,只是现在有一个EXC_BAD_ACCESS错误。这意味着应用程序有一个内存管理的问题。

我的 App Crashed, 怎么办? – Part 1

内存相关崩溃的来源往往是难以确定,因为可能已经做了很多早期的计划。如果一个故障代码段破坏的存储器结构,这样做的结果可能不会出现,直到很久以后,在一个完全不同的地方。

其实,这个错误可能永远不会出现在你的所有在测试时,只张牙舞爪对客户的设备。你不希望这样的事情发生!

这种特殊的崩溃,但很容易解决。如果你看一下源代码编辑器,Xcode中已经警告你这条线一直。请参见上的黄色三角形左边旁行号?这表明一个编译器警告。如果你点击黄色三角形,Xcode中应该弹出一个“修复”的建议是这样的:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UINavigationController *navController = (UINavigationController *)self.window.rootViewController;
    MainViewController *viewController = (MainViewController *)navController.topViewController;
    arrayWithObjects:@"One", @"Two",nil];//添加nil 结尾
    return YES;

}
           

未完待续。。。