天天看點

ios崩潰的解決

http://blog.csdn.net/gnicky/article/details/7459238

沒有任何crash發生,在我們來看是最好的:你工作愉快,對您的應用程式,一切都很好!然後突然 - 噗! - 崩潰。 aaargh!! (提示悲傷的小提琴。)

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

修複崩潰并不需要是很難的。如果你吓壞了,并開始随意改變事情,你很可能使局勢惡化;你如果期望隻說出正确的咒語,希望錯誤會奇迹般地消失,你在做夢。相反,你需要采取有條不紊的方法,并學習如何通過自己的方式找崩潰的原因。

首先是為了找出确切位置在您的代碼崩潰發生在哪個檔案,哪一行。 Xcode調試将幫助你,但你需要了解如何使物盡其用,這正是本教程将告訴你!

iOS指南系列:如何解決奔潰問題

iOS指南系列:如何解決奔潰問題-關于記憶體通路

iOS指南系列:如何解決奔潰問題-關于記憶體通路續

iOS指南系列:如何解決奔潰問題-關于記憶體通路續

入門

下載下傳示例項目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,應用程式的主線程,因為在那裡,你會做你的大部分工作。如果您的代碼使用隊列或背景線程,那麼應用程式可能會崩潰在其他線程。

ios崩潰的解決

目前,Xcode的突出問題的根源在main.m main()函數。這并不能告訴你非常多,是以你必須挖得更深一些。

看到更多的調用堆棧,拖動滑塊在底部的調試導航的最右邊。在崩潰的時刻,将顯示完整的調用堆棧:

ios崩潰的解決

構造出調用順序圖:

ios崩潰的解決

所有這些函數和方法調用堆棧中,除了為main(),是灰色的。這是因為他們從内置在iOS架構。有沒有為他們提供的源代碼。

你源代碼是唯一在這個堆棧跟蹤main.m,是以這是什麼Xcode的源代碼編輯器中顯示,盡管它不是一個真正的崩潰的真正來源。這往往混淆了新的開發,但在一分鐘内,我會告訴你如何做,看到它的真實意義。

嘗試一下,單擊“從堆棧跟蹤的其他項目中的任何一個,你會看到一堆彙編代碼可能不會給你太大的意義:

ios崩潰的解決

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

異常斷點

那麼,你如何找到應用程式崩潰的代碼行嗎?好了,隻要你像這樣的堆棧跟蹤,異常被抛出的應用程式。 (你可以告訴,因為調用堆棧中的職能之一,被命名為objc_exception_rethrow)。

發生異常捕獲程式時,做一些不應該做的。你現在看到的是這個異常的後果:應用程式做了錯事,已引發異常,Xcode中顯示您的結果。理想的情況下,你希望看到的正是這種異常被抛出。

幸運的是,你可以告訴Xcode暫停在剛才那一瞬間的方案,使用一個異常斷點。斷點是調試工具,停在一個特定的時刻,根據你的計劃。在本教程的第二部分,你會看到他們,但現在你會使用特定的斷點将暫停程式,隻是前一個異常被抛出。

總結來說,下面的步驟就是啟用first-chance exception當第一次 錯誤抛出就斷下。。。

ios崩潰的解決

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

ios崩潰的解決

A new breakpoint will be added to the list:

ios崩潰的解決

[cpp]  view plain copy

  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:

ios崩潰的解決

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.

ios崩潰的解決

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呢?請聽下回分解

ios崩潰的解決

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:

ios崩潰的解決

當我們有源代碼的時候就可以看到代碼啦。。。。