崩潰日志詳解下

異常編碼

在研究真實閃退場景之前,還有一點需要重點介紹一下:就是那些有趣的異常編碼 。

你可以在報告的異常部分——前面代碼的第3部分找到異常編碼。有些編碼比較常見。

通常,異常編碼以一些文字開頭,緊接著是一個或多個十六進制值,此數(shù)值正是說明閃退根本性質(zhì)的所在。? 從這些編碼中,可以區(qū)分出閃退是因為程序錯誤、非法內(nèi)存訪問或者是其他原因。

下面是一些常見的異常編碼:

0x8badf00d: 讀做 “ate bad food”! (把數(shù)字換成字母,是不是很像 :p)該編碼表示應用是因為發(fā)生watchdog超時而被iOS終止的。? 通常是應用花費太多時間而無法啟動、終止或響應用系統(tǒng)事件。

0xbad22222: 該編碼表示 VoIP 應用因為過于頻繁重啟而被終止。

0xdead10cc: 讀做 “dead lock”!該代碼表明應用因為在后臺運行時占用系統(tǒng)資源,如通訊錄數(shù)據(jù)庫不釋放而被終止 。

0xdeadfa11: 讀做 “dead fall”! 該代碼表示應用是被用戶強制退出的。根據(jù)蘋果文檔, 強制退出發(fā)生在用戶長按開關按鈕直到出現(xiàn) “滑動來關機”, 然后長按 Home按鈕。強制退出將產(chǎn)生 包含0xdeadfa11 異常編碼的崩潰日志, 因為大多數(shù)是強制退出是因為應用阻塞了界面。

注意: 在后臺任務列表中關閉已掛起的應用不會產(chǎn)生崩潰日志。 一旦應用被掛起,它何時被終止都是合理的。所以不會產(chǎn)生崩潰日志。

大展身手的時候到了!

好了! 你已經(jīng)學習了所有分析崩潰日志和修復錯誤的基礎知識!

假設你剛進入Rage-O-Rage有限公司工作。該公司有一個在App Store上熱銷的應用,叫 Rage Masters。

你的老板安迪要你幫忙解決幾個用戶經(jīng)常抱怨閃退問題。你的任務就是研究這些閃退,符號化用戶提供的崩潰日志,查找問題所在,并修復之。

你可以從? 這里下載應用的源代碼。

注意: 如果你想自己重新生成崩潰報告,請遵照以下指引:

下載源碼然后在Xcode中打開工程文件。

使用正確的provisioning profile連接到iOS設備。

從Xcode工具欄上選擇iOS設備——不是模擬器作為target,然后構建應用。

當你在設備上到默認頁面(應用的全屏圖片)時,立即在Xcode上點擊停止按鈕。

關閉 Xcode。

在設備上直接打開應用。

測試場景,完成后連接設備到電腦上,通過Xcode獲取崩潰日志。

場景 1: 糟糕的代碼

一封來自用戶的郵件: “大哥,你的應用就是一坨屎! 我將其下載到我自己的iPod Touch和iPhone上,還下載到我兒子的iPod Touch上。在所有的設備上,都是還沒打開就閃退了……”

別一封來自用戶的郵件說, “我下載了你們的應用,一打開就閃退。真悲催…”

另一封郵件說得更明確:”你們的應用不能運行。我把它下載到我和妻子的設備上。所有設備都是 一打開就閃退了…”

好吧,別灰心! 這些意見藏著什么玄機呢?讓我們看看崩潰日志吧:

Incident Identifier: 85833DBA-3DF7-43EE-AF80-4E5C51091F42

CrashReporter Key:? 5a56599d836c4f867f6eec76afee451bf9ae5f31

Hardware Model:? ? ? iPhone4,1

Process:? ? ? ? Rage Masters [20067]

Path:? ? ? ? ? ? /var/mobile/Applications/B2121A89-3D1F-4E61-BB18-5511E1DC150F/Rage Masters.app/Rage Masters

Identifier:? ? ? Rage Masters

Version:? ? ? ? ??? (???)

Code Type:? ? ? ARM (Native)

Parent Process:? launchd [1]

Date/Time:? ? ? 2012-11-03 13:37:31.148 -0400

OS Version:? ? ? iOS 6.0 (10A403)

Report Version:? 104

Exception Type:? 00000020

Exception Codes: 0x000000008badf00d

Highlighted Thread:? 0

Application Specific Information:

Soheil-Azarpour.Rage-Masters failed to launch in time

Elapsed total CPU time (seconds): 8.030 (user 8.030, system 0.000), 20% CPU

Elapsed application CPU time (seconds): 3.840, 10% CPU

Thread 0 name:? Dispatch queue: com.apple.main-thread

Thread 0:

0? libsystem_kernel.dylib? ? ? ? ? ? 0x327f2eb4 mach_msg_trap + 20

1? libsystem_kernel.dylib? ? ? ? ? ? 0x327f3048 mach_msg + 36

2? CoreFoundation? ? ? ? ? ? ? ? ? ? 0x36bd4040 __CFRunLoopServiceMachPort + 124

3? CoreFoundation? ? ? ? ? ? ? ? ? ? 0x36bd2d9e __CFRunLoopRun + 878

4? CoreFoundation? ? ? ? ? ? ? ? ? ? 0x36b45eb8 CFRunLoopRunSpecific + 352

5? CoreFoundation? ? ? ? ? ? ? ? ? ? 0x36b45d44 CFRunLoopRunInMode + 100

6? CFNetwork? ? ? ? ? ? ? ? ? ? ? ? 0x32ac343e CFURLConnectionSendSynchronousRequest + 330

7? Foundation? ? ? ? ? ? ? ? ? ? ? ? 0x346e69ba +[NSURLConnection sendSynchronousRequest:returningResponse:error:] + 242

8? Rage Masters? ? ? ? ? ? ? ? ? ? ? 0x000ea1c4 -[RMAppDelegate application:didFinishLaunchingWithOptions:] (RMAppDelegate.m:36)

9? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x37f30ad4 -[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 248

10? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x37f3065e -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1186

11? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x37f28846 -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 694

12? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x37ed0c3c -[UIApplication handleEvent:withNewEvent:] + 1000

13? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x37ed06d0 -[UIApplication sendEvent:] + 68

14? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x37ed011e _UIApplicationHandleEvent + 6150

15? GraphicsServices? ? ? ? ? ? ? ? ? 0x370835a0 _PurpleEventCallback + 588

16? GraphicsServices? ? ? ? ? ? ? ? ? 0x370831ce PurpleEventCallback + 30

17? CoreFoundation? ? ? ? ? ? ? ? ? ? 0x36bd4170 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 32

18? CoreFoundation? ? ? ? ? ? ? ? ? ? 0x36bd4112 __CFRunLoopDoSource1 + 134

19? CoreFoundation? ? ? ? ? ? ? ? ? ? 0x36bd2f94 __CFRunLoopRun + 1380

20? CoreFoundation? ? ? ? ? ? ? ? ? ? 0x36b45eb8 CFRunLoopRunSpecific + 352

21? CoreFoundation? ? ? ? ? ? ? ? ? ? 0x36b45d44 CFRunLoopRunInMode + 100

22? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x37f27480 -[UIApplication _run] + 664

23? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x37f242fc UIApplicationMain + 1116

24? Rage Masters? ? ? ? ? ? ? ? ? ? ? 0x000ea004 main (main.m:16)

25? libdyld.dylib? ? ? ? ? ? ? ? ? ? 0x3b630b1c start + 0

發(fā)現(xiàn)問題了嗎? 異常編碼是 0x000000008badf00d,還有后面的報告:

Application Specific Information:

Soheil-Azarpour.Rage-Masters failed to launch in time

Elapsed total CPU time (seconds): 8.030 (user 8.030, system 0.000), 20% CPU

Elapsed application CPU time (seconds): 3.840, 10% CPU

這說明應用在啟動時就閃退了,iOS的watchdog機制終止了應用。帥! 找到問題了,但是為什會發(fā)生這樣的事呢?

接著往下看日志。 從下向上讀回溯日志。最底下的幀 (frame 25: libdyld.dylib)是最先調(diào)用的,然后是幀24, Rage Masters, main (main.m:16) ,依此類推。

跟應用源代碼相關的幀是最重要的。忽略掉系統(tǒng)庫和框架。下一個與代碼相關的幀是:

8? ? Rage Masters? ? 0x0009f244 -[RMAppDelegate application:didFinishLaunchingWithOptions:] (RMAppDelegate.m:35)

應用在執(zhí)行RMAppDelegate (RMAppDelegate.m:35)類 application:didFinishLaunchingWithOptions: 方法第35 行代碼時閃退。打開Xcode看看那行代碼:

NSData *directoryData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];

就是它了! 同步調(diào)用web服務?! 在主線程上?! 在? application:didFinishLaunchingWithOptions: 方法上?!! 誰寫的代碼呀?!

Network calls on the main thread makes kittens sad.

Network calls on the main thread makes kittens sad.

不管如何,問題得你來修復了。這個調(diào)用必需異步進行,甚至更理想的情況是,在 application:didFinishLaunchingWithOptions:返回YES之后的其他部分再執(zhí)行Web服務。

在其他地方調(diào)用可能需要比較多的修改。當下,我們只要使應用不閃退就行??梢栽谌蘸笤賹崿F(xiàn)更好的設計。 將上面那行討厭的代碼(及其下面的三行代碼)換成下面這個異步的版本吧:

[NSURLConnection sendAsynchronousRequest:request

queue:[NSOperationQueue mainQueue]

completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)

{

NSURL *cacheDirectory = [[[NSFileManager defaultManager] URLsForDirectory:NSUserDirectory inDomains:NSCachesDirectory] lastObject];

NSURL *filePath = [NSURL URLWithString:kDirectoryFile relativeToURL:cacheDirectory];

[data writeToFile:[filePath absoluteString] atomically:YES];

}];

場景 2: 無法響應事件的按鈕

一名用戶說: “我不能將某個rage master添加到書簽里面。我想添加的時候應用就閃退…”

用一名用戶說 :”書簽不能用 … 在詳細頁面上,點擊書簽按鈕,應用就閃退了!”

上面的抱怨說得不是很清楚,引起問題的原因肯定有多樣??纯幢罎⑷罩?

Incident Identifier: 3AAA63CC-3088-41CC-84D9-82FE03F9F354

CrashReporter Key:? 5a56599d836c4f867f6eec76afee451bf9ae5f31

Hardware Model:? ? ? iPhone4,1

Process:? ? ? ? Rage Masters [20090]

Path:? ? ? ? ? ? /var/mobile/Applications/B2121A89-3D1F-4E61-BB18-5511E1DC150F/Rage Masters.app/Rage Masters

Identifier:? ? ? Rage Masters

Version:? ? ? ? ??? (???)

Code Type:? ? ? ARM (Native)

Parent Process:? launchd [1]

Date/Time:? ? ? 2012-11-03 13:39:00.081 -0400

OS Version:? ? ? iOS 6.0 (10A403)

Report Version:? 104

Exception Type:? EXC_CRASH (SIGABRT)

Exception Codes: 0x0000000000000000, 0x0000000000000000

Crashed Thread:? 0

Last Exception Backtrace:

0? CoreFoundation? ? ? ? ? ? ? ? ? ? 0x36bff29e __exceptionPreprocess + 158

1? libobjc.A.dylib? ? ? ? ? ? ? ? ? 0x34f0f97a objc_exception_throw + 26

2? CoreFoundation? ? ? ? ? ? ? ? ? ? 0x36c02e02 -[NSObject(NSObject) doesNotRecognizeSelector:] + 166

3? CoreFoundation? ? ? ? ? ? ? ? ? ? 0x36c0152c ___forwarding___ + 388

4? CoreFoundation? ? ? ? ? ? ? ? ? ? 0x36b58f64 _CF_forwarding_prep_0 + 20

5? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x37fbb0a8 -[UIApplication sendAction:to:from:forEvent:] + 68

6? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x37fbb05a -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 26

7? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x37fbb038 -[UIControl sendAction:to:forEvent:] + 40

8? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x37fba8ee -[UIControl(Internal) _sendActionsForEvents:withEvent:] + 498

9? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x37fbade4 -[UIControl touchesEnded:withEvent:] + 484

10? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x37ee35f4 -[UIWindow _sendTouchesForEvent:] + 520

11? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x37ed0804 -[UIApplication sendEvent:] + 376

12? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x37ed011e _UIApplicationHandleEvent + 6150

13? GraphicsServices? ? ? ? ? ? ? ? ? 0x3708359e _PurpleEventCallback + 586

14? GraphicsServices? ? ? ? ? ? ? ? ? 0x370831ce PurpleEventCallback + 30

15? CoreFoundation? ? ? ? ? ? ? ? ? ? 0x36bd416e __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 30

16? CoreFoundation? ? ? ? ? ? ? ? ? ? 0x36bd4112 __CFRunLoopDoSource1 + 134

17? CoreFoundation? ? ? ? ? ? ? ? ? ? 0x36bd2f94 __CFRunLoopRun + 1380

18? CoreFoundation? ? ? ? ? ? ? ? ? ? 0x36b45eb8 CFRunLoopRunSpecific + 352

19? CoreFoundation? ? ? ? ? ? ? ? ? ? 0x36b45d44 CFRunLoopRunInMode + 100

20? GraphicsServices? ? ? ? ? ? ? ? ? 0x370822e6 GSEventRunModal + 70

21? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x37f242fc UIApplicationMain + 1116

22? Rage Masters? ? ? ? ? ? ? ? ? ? ? 0x000ca004 main (main.m:16)

23? libdyld.dylib? ? ? ? ? ? ? ? ? ? 0x3b630b1c start + 0

異常代碼是SIGABRT。通常,? SIGABRT 異常是由于某個對象接收到未實現(xiàn)的消息引起的。 或者,用簡單的話說,在某個對象上調(diào)用了不存在的方法。

這種情況一般不會發(fā)生,因為A對象調(diào)用了B方法,如果B方法不存在,編譯器會報錯。但是,如果你是使用selector間接調(diào)用方法的,編譯器則無法檢測對象是否存在該方法了。

回到崩潰日志。它指出閃退發(fā)生在編號為0的線程上。 這意味著很可能是在主線程上調(diào)用了某個對象沒有實現(xiàn)的方法。

如果你接著閱讀回溯日志,會發(fā)現(xiàn)跟你的代碼相關的只有幀22, main.m:16. 這沒有多大幫助。 :[

繼續(xù)向上查看框架調(diào)用,出現(xiàn)這個:

2? ? CoreFoundation? ? 0x36c02e02 -[NSObject(NSObject) doesNotRecognizeSelector:] + 166

這不是你自己寫的代碼。但至少它確認了是對象調(diào)用了一個沒有實現(xiàn)的方法。

回到 RMDetailViewController.m文件, 因為那是書簽按鈕實現(xiàn)動作的地方。 找到書簽功能代碼:

-(IBAction)bookmarkButtonPressed {

self.master.isBookmarked = !self.master.isBookmarked;

// Update shared bookmarks

if (self.master.isBookmarked)

[[RMBookmarks sharedBookmarks] bookmarkMaster:self.master];

else

[[RMBookmarks sharedBookmarks] unbookmarkMaster:self.master];

// Update UI

[self updateBookmarkImage];

}

看起來沒什么問題,再檢查一下storyboard (XIB文件) ,確認按鈕連接的正確性。

就是它了! 在? MainStoryboard.storyboard,按鈕連接的是 bookmarkButtonPressed: 而不是bookmarkButtonPressed (注意后面的分號說明方法有一個參數(shù))。 只要將上面的方法簽名修改成這樣就能修復問題了:

-(IBAction)bookmarkButtonPressed:(id)sender {

// Remain unchanged..

}

當然,你也可以簡單地在XIB文件上刪除錯誤的連接,然后重新連接方法,使XIB文件連接到正確的方法上。兩者方法都行。

又處理了一個閃退問題,好樣的。:]

場景 3: 表格上的Bug

另一用戶抱怨道, “在書簽視圖上無法刪除書簽…” 還有另一用戶抱怨同樣的問題, “當我試圖刪除書簽時,應用閃退…”

這些郵件沒什么作用,還是看看崩潰日志!

Incident Identifier: 5B62D681-D8FE-41FE-8D52-AB7E6D6B2AC7

CrashReporter Key:? 5a56599d836c4f867f6eec76afee451bf9ae5f31

Hardware Model:? ? ? iPhone4,1

Process:? ? ? ? Rage Masters [20088]

Path:? ? ? ? ? ? /var/mobile/Applications/B2121A89-3D1F-4E61-BB18-5511E1DC150F/Rage Masters.app/Rage Masters

Identifier:? ? ? Rage Masters

Version:? ? ? ? ??? (???)

Code Type:? ? ? ARM (Native)

Parent Process:? launchd [1]

Date/Time:? ? ? 2012-11-03 13:38:45.762 -0400

OS Version:? ? ? iOS 6.0 (10A403)

Report Version:? 104

Exception Type:? EXC_CRASH (SIGABRT)

Exception Codes: 0x0000000000000000, 0x0000000000000000

Crashed Thread:? 0

Last Exception Backtrace:

0? CoreFoundation? ? ? ? ? ? ? ? ? ? 0x36bff29e __exceptionPreprocess + 158

1? libobjc.A.dylib? ? ? ? ? ? ? ? ? 0x34f0f97a objc_exception_throw + 26

2? CoreFoundation? ? ? ? ? ? ? ? ? ? 0x36bff158 +[NSException raise:format:arguments:] + 96

3? Foundation? ? ? ? ? ? ? ? ? ? ? ? 0x346812aa -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 86

4? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x37f04b7e -[UITableView(_UITableViewPrivate) _endCellAnimationsWithContext:] + 7690

5? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x3803a4a2 -[UITableView deleteRowsAtIndexPaths:withRowAnimation:] + 22

6? Rage Masters? ? ? ? ? ? ? ? ? ? ? 0x000fd9ca -[RMBookmarksViewController tableView:commitEditingStyle:forRowAtIndexPath:] (RMBookmarksViewController.m:68)

7? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x3809a5d4 -[UITableView(UITableViewInternal) animateDeletionOfRowWithCell:] + 80

8? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x37fbb0a8 -[UIApplication sendAction:to:from:forEvent:] + 68

9? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x37fbb05a -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 26

10? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x37fbb038 -[UIControl sendAction:to:forEvent:] + 40

11? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x37fba8ee -[UIControl(Internal) _sendActionsForEvents:withEvent:] + 498

12? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x37fbb0a8 -[UIApplication sendAction:to:from:forEvent:] + 68

13? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x37fbb05a -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 26

14? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x37fbb038 -[UIControl sendAction:to:forEvent:] + 40

15? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x37fba8ee -[UIControl(Internal) _sendActionsForEvents:withEvent:] + 498

16? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x37fbade4 -[UIControl touchesEnded:withEvent:] + 484

17? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x37ee35f4 -[UIWindow _sendTouchesForEvent:] + 520

18? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x37ed0804 -[UIApplication sendEvent:] + 376

19? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x37ed011e _UIApplicationHandleEvent + 6150

20? GraphicsServices? ? ? ? ? ? ? ? ? 0x3708359e _PurpleEventCallback + 586

21? GraphicsServices? ? ? ? ? ? ? ? ? 0x370831ce PurpleEventCallback + 30

22? CoreFoundation? ? ? ? ? ? ? ? ? ? 0x36bd416e __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 30

23? CoreFoundation? ? ? ? ? ? ? ? ? ? 0x36bd4112 __CFRunLoopDoSource1 + 134

24? CoreFoundation? ? ? ? ? ? ? ? ? ? 0x36bd2f94 __CFRunLoopRun + 1380

25? CoreFoundation? ? ? ? ? ? ? ? ? ? 0x36b45eb8 CFRunLoopRunSpecific + 352

26? CoreFoundation? ? ? ? ? ? ? ? ? ? 0x36b45d44 CFRunLoopRunInMode + 100

27? GraphicsServices? ? ? ? ? ? ? ? ? 0x370822e6 GSEventRunModal + 70

28? UIKit? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x37f242fc UIApplicationMain + 1116

29? Rage Masters? ? ? ? ? ? ? ? ? ? ? 0x000fb004 main (main.m:16)

30? libdyld.dylib? ? ? ? ? ? ? ? ? ? 0x3b630b1c start + 0

這看起來跟前面那個崩潰日志很像。是另一個SIGABRT 異常。 你可能想知道是否是相同的問題:發(fā)送信息到一個沒有實現(xiàn)相應方法的對象?

讓我們從回溯日志看看哪些方法被調(diào)用了。從底部開始,你的源代碼最后被調(diào)用的是幀 6:

6? ? Rage Masters? ? 0x00088c66 -[RMBookmarksViewController tableView:commitEditingStyle:forRowAtIndexPath:] (RMBookmarksViewController.m:68)

這是UITableViewDataSource 的一個方法. 呵呵?! 毫無疑問蘋果已經(jīng)實現(xiàn)了該方法 —— 你可以重載它, 但不像是還沒有實現(xiàn)。而且,這是個可選的委派方法。 所以問題不是調(diào)用了一個沒有實現(xiàn)的方法。

再看看上面的幾個幀:

3? ? Foundation? ? 0x346812aa -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 86

4? ? UIKit? ? ? ? 0x37f04b7e -[UITableView(_UITableViewPrivate) _endCellAnimationsWithContext:] + 7690

5? ? UIKit? ? ? ? 0x3803a4a2 -[UITableView deleteRowsAtIndexPaths:withRowAnimation:] + 22

幀 5, UITableView調(diào)用了它自己的另一個方法? deleteRowsAtIndexPaths:withRowAnimation: 然后是看起來像蘋果內(nèi)部方法的 _endCellAnimationsWithContext: 被調(diào)用。然后Foundation framework發(fā)生異常 handleFailureInMethod:object:file:lineNumber:description:.

這些分析結合用戶的抱怨,看起來是你在處理UITableView刪除行過程中有Bug?;氐絏code。你知道看哪里嗎 ? 能從崩潰日志中判斷出來? 就是 RMBookmarksViewController.m文件的第68行:

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {

[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];

}

發(fā)現(xiàn)問題了嗎? 給你點時間,仔細看一下。

找到了吧! 數(shù)據(jù)源呢? 代碼在表格視圖上刪除了一行,但并沒有修改背后的數(shù)據(jù)源。把上面的代碼替換成下面的就能修復問題了:

-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {

RMMaster *masterToDelete = [bookmarks objectAtIndex:indexPath.row];

[bookmarks removeObject:masterToDelete];

[[RMBookmarks sharedBookmarks] unbookmarkMaster:masterToDelete];

[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];

}

搞定了!走起,討厭的 bug!!

場景 4: 吃棒棒糖時閃退!

用戶郵件說, “當rage master吃棒棒糖時應用就閃退…” 另一用戶說, “我讓rage master 吃棒棒糖,沒幾次應用就閃退了!”

崩潰日志如下:

Incident Identifier: 081E58F5-95A8-404D-947B-5E104B6BC1B1

CrashReporter Key:? 5a56599d836c4f867f6eec76afee451bf9ae5f31

Hardware Model:? ? ? iPhone4,1

OS Version:? ? ? ? ? iPhone OS 6.0 (10A403)

Kernel Version:? ? ? Darwin Kernel Version 13.0.0: Sun Aug 19 00:28:05 PDT 2012; root:xnu-2107.2.33~4/RELEASE_ARM_S5L8940X

Date:? ? ? ? ? ? ? ? 2012-11-03 13:39:59 -0400

Time since snapshot: 4353 ms

Free pages:? ? ? ? 968

Active pages:? ? ? 7778

Inactive pages:? ? 4005

Throttled pages:? 92319

Purgeable pages:? 0

Wired pages:? ? ? 23347

Largest process:? Rage Masters

Processes

Name? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? rpages? ? ? recent_max? ? ? [reason]? ? ? ? ? (state)

lsd <6a9f5b5f36b23fc78f87b6d8f1f49a9d>? ? ? ? ? 331? ? ? ? ? ? ? 331? ? ? ? [vm]? ? ? ? (daemon) (idle)

afcd? ? ? ? ? 141? ? ? ? ? ? ? 141? ? ? ? [vm]? ? ? ? (daemon) (idle)

itunesstored <4e0cd9f873de3435b4119c48b2d6d13d>? ? ? ? 1761? ? ? ? ? ? 1761? ? ? ? [vm]? ? ? ? (daemon) (idle)

softwareupdatese <2bc4b5ae016431c98d3b34f81027d0ae>? ? ? ? ? 311? ? ? ? ? ? ? 311? ? ? ? [vm]? ? ? ? (daemon) (idle)

Amazon <4600481f07ec3e59a925319b7f67ba14>? ? ? ? 2951? ? ? ? ? ? 2951? ? ? ? [vm]? ? ? ? (suspended)

accountsd? ? ? ? ? 519? ? ? ? ? ? ? 519? ? ? ? [vm]? ? ? ? (daemon) (idle)

coresymbolicatio? ? ? ? ? 126? ? ? ? ? ? ? 126? ? ? ? [vm]? ? ? ? (daemon) (idle)

Skype <504cf2fe60cb3cdea8273e74df09836b>? ? ? ? 3187? ? ? ? ? ? 3187? ? ? ? [vm]? ? ? ? (background)

MobileMail? ? ? ? 14927? ? ? ? ? ? 14927? ? ? ? [vm]? ? ? ? (continuous)

MobileSMS <46778de076363d67aeea207464cfc581>? ? ? ? 2134? ? ? ? ? ? 2134? ? ? ? [vm]? ? ? ? (background)

MobilePhone <3fca241f2a193d0fb8264218d296ea41>? ? ? ? 2689? ? ? ? ? ? 2689? ? ? ? [vm]? ? ? ? (continuous)

librariand? ? ? ? ? 317? ? ? ? ? ? ? 317? ? ? ? [vm]? ? ? ? (daemon)

kbd <3e7136ddcefc3d77a01499db593466cd>? ? ? ? ? 616? ? ? ? ? ? ? 616? ? ? ? [vm]? ? ? ? (daemon)

tccd? ? ? ? ? 224? ? ? ? ? ? ? 224? ? ? ? [vm]? ? ? ? (daemon)

Rage Masters <90b45d6281e934209c5b06cf7dc4d492>? ? ? ? 28591? ? ? ? ? ? 28591? ? ? ? [vm]? ? ? ? (frontmost) (resume)

ptpd <04a56fce67053c57a7979aeea8e5a7ea>? ? ? ? ? 879? ? ? ? ? ? ? 879? ? ? ? ? ? ? ? ? ? ? (daemon)

iaptransportd? ? ? ? ? 230? ? ? ? ? ? ? 230? ? ? ? ? ? ? ? ? ? ? (daemon)

locationd <892cd1c9ffa43c99a82dba197be5f09e>? ? ? ? 1641? ? ? ? ? ? 1641? ? ? ? ? ? ? ? ? ? ? (daemon)

syslogd? ? ? ? ? 237? ? ? ? ? ? ? 237? ? ? ? ? ? ? ? ? ? ? (daemon)

mediaserverd <80657170daca32c9b8f3a6b1faac43a2>? ? ? ? 4869? ? ? ? ? ? 4869? ? ? ? ? ? ? ? ? ? ? (daemon)

dataaccessd <2a3f6a518f3f3646bf35eddd36f25005>? ? ? ? 1786? ? ? ? ? ? 1786? ? ? ? ? ? ? ? ? ? ? (daemon)

aosnotifyd? ? ? ? ? 549? ? ? ? ? ? ? 549? ? ? ? ? ? ? ? ? ? ? (daemon)

wifid <9472b090746237998cdbb9b34f090d0c>? ? ? ? ? 455? ? ? ? ? ? ? 455? ? ? ? ? ? ? ? ? ? ? (daemon)

SpringBoard <27372aae101f3bbc87804edc10314af3>? ? ? ? 18749? ? ? ? ? ? 18749

backboardd <5037235f295b33eda98eb5c72c098858>? ? ? ? 5801? ? ? ? ? ? 5801? ? ? ? ? ? ? ? ? ? ? (daemon)

UserEventAgent <6edfd8d8dba23187b05772dcdfc94f90>? ? ? ? ? 601? ? ? ? ? ? ? 601? ? ? ? ? ? ? ? ? ? ? (daemon)

mediaremoted <4ff39c50c684302492e396ace813cb25>? ? ? ? ? 293? ? ? ? ? ? ? 293? ? ? ? ? ? ? ? ? ? ? (daemon)

pasteboardd <8a4279b78e4a321f84a076a711dc1c51>? ? ? ? ? 176? ? ? ? ? ? ? 176? ? ? ? ? ? ? ? ? ? ? (daemon)

springboardservi? ? ? ? ? ? 0? ? ? ? ? ? ? ? 0? ? ? ? ? ? ? ? ? ? ? (daemon)

syslog_relay <45e9844605d737a08368b5215bb54426>? ? ? ? ? ? 0? ? ? ? ? ? ? ? 0? ? ? ? ? ? ? ? ? ? ? (daemon)

DTMobileIS <23303ca402aa3705870b01a9047854ea>? ? ? ? ? ? 0? ? ? ? ? ? ? ? 0? ? ? ? ? ? ? ? ? ? ? (daemon)

notification_pro <845b7beebc8538ca9ceef731031983b7>? ? ? ? ? 169? ? ? ? ? ? ? 169? ? ? ? ? ? ? ? ? ? ? (daemon)

syslog_relay <45e9844605d737a08368b5215bb54426>? ? ? ? ? ? 0? ? ? ? ? ? ? ? 0? ? ? ? ? ? ? ? ? ? ? (daemon)

ubd <74dc476d1785300e9fcda555fcb8d774>? ? ? ? ? 976? ? ? ? ? ? ? 976? ? ? ? ? ? ? ? ? ? ? (daemon)

twitterd <4b4946378a9c397d8250965d17055b8e>? ? ? ? ? 730? ? ? ? ? ? ? 730? ? ? ? ? ? ? ? ? ? ? (daemon)

configd <4245d73a9e96360399452cf6b8671844>? ? ? ? ? 809? ? ? ? ? ? ? 809? ? ? ? ? ? ? ? ? ? ? (daemon)

absinthed.N94 <7f4164c844fa340caa940b863c901aa9>? ? ? ? ? 99? ? ? ? ? ? ? 99? ? ? ? ? ? ? ? ? ? ? (daemon)

filecoordination? ? ? ? ? 226? ? ? ? ? ? ? 226? ? ? ? ? ? ? ? ? ? ? (daemon)

distnoted? ? ? ? ? 137? ? ? ? ? ? ? 137? ? ? ? ? ? ? ? ? ? ? (daemon)

apsd <94d8051dd5f5362f82d775bc279ae608>? ? ? ? ? 373? ? ? ? ? ? ? 373? ? ? ? ? ? ? ? ? ? ? (daemon)

networkd <0032f46009f53a6c80973fe153d1a588>? ? ? ? ? 219? ? ? ? ? ? ? 219? ? ? ? ? ? ? ? ? ? ? (daemon)

aggregated <8c3c991dc4153bc38aee1e841864d088>? ? ? ? ? 112? ? ? ? ? ? ? 112? ? ? ? ? ? ? ? ? ? ? (daemon)

BTServer? ? ? ? ? 522? ? ? ? ? ? ? 522? ? ? ? ? ? ? ? ? ? ? (daemon)

fairplayd.N94 <7bd896bd00783a48906090d05cf1c86a>? ? ? ? ? 210? ? ? ? ? ? ? 210? ? ? ? ? ? ? ? ? ? ? (daemon)

fseventsd <996cc4ca03793184aea8d781b55bce08>? ? ? ? ? 384? ? ? ? ? ? ? 384? ? ? ? ? ? ? ? ? ? ? (daemon)

imagent <1e68080947be352590ce96b7a1d07b2f>? ? ? ? ? 586? ? ? ? ? ? ? 586? ? ? ? ? ? ? ? ? ? ? (daemon)

mDNSResponder <3e557693f3073697a58da6d27a827d97>? ? ? ? ? 295? ? ? ? ? ? ? 295? ? ? ? ? ? ? ? ? ? ? (daemon)

lockdownd? ? ? ? ? 389? ? ? ? ? ? ? 389? ? ? ? ? ? ? ? ? ? ? (daemon)

powerd <2d2ffed5e69638aeba1b92ef124ed861>? ? ? ? ? 174? ? ? ? ? ? ? 174? ? ? ? ? ? ? ? ? ? ? (daemon)

CommCenter <1f425e1e897d32e8864fdd8eeaa803a8>? ? ? ? 2212? ? ? ? ? ? 2212? ? ? ? ? ? ? ? ? ? ? (daemon)

notifyd <51c0e03da8a93ac8a595442fcaac531f>? ? ? ? ? 211? ? ? ? ? ? ? 211? ? ? ? ? ? ? ? ? ? ? (daemon)

ReportCrash <8c32f231b2ed360bb151b2563bcaa363>? ? ? ? ? 337? ? ? ? ? ? ? 337? ? ? ? ? ? ? ? ? ? ? (daemon)

這日志跟我們前面見到的相差很多。

這個一個來自iOS 6的低內(nèi)存崩潰日志。正如我們前面所說的,低內(nèi)存崩潰日志與其他類型的崩潰日志很不一樣,它們不指向特定的文件和代碼行。相反,它們畫出了閃退時設備上的內(nèi)存使用情況的圖表。

至少,頭部還是跟其他崩潰日志很像的:? 提供了 Incident Identifier, CrashReporter Key, Hardware Model, OS Version等信息。

接下來部分是低內(nèi)存崩潰日志特有的:

Free pages 指可用內(nèi)存頁數(shù)。每頁大小約是4KB, 上面的日志中,可用內(nèi)存約為3,872 KB (或者說 3.9 MB)。

Purgeable pages 是那部分可被清除或重用的內(nèi)存。在上面的日志中,是0KB。

Largest process是閃退時使用大部分內(nèi)存的應用名稱,在上面的日志中,正是你的應用!

Processes顯示了閃退時各進程列表,還包含內(nèi)存使用量。包含進程名 (第一列), 進程唯一標識符(第二名), 進程使用的內(nèi)存頁數(shù)(第三列)。最后一列是每個應用的狀態(tài)。通常,發(fā)生閃退的應用的狀態(tài)是 frontmost。 這里是 Rage Masters, 使用28591 頁 (or 114.364 MB) 內(nèi)存——這內(nèi)存太多了!

通過,最大進程和frontmost狀態(tài)的應用是相同的, 而且也是引起低內(nèi)存閃退的應用進程。但是也可能看到最大進程和 frontmost狀態(tài)應用不同的例子。比如,如果最大進程是SpringBoard, 忽略它 , 因為 SpringBoard 進程是顯示主屏幕的應用,出現(xiàn)在你雙擊home按鈕等情況,而且它是一直活動的。

低內(nèi)存發(fā)生時,iOS向活動的應用發(fā)出低內(nèi)存警告并終止后臺應用。如果前臺應用仍然繼續(xù)增長內(nèi)存,iOS將終止它。

為了查找低內(nèi)存問題的原因,你必需使用Instruments剖析應用。如果你不知道怎么做,可以看一下我們 一篇關于這個方面的教程.。 :] 另外, 你也可以走捷徑,響應低內(nèi)存警告通知,以解決部分閃退問題。

回到Xcode查看RMLollipopLicker.m文件。 這是實現(xiàn)吃棒棒糖的視圖控制器??纯丛创a:

#import "RMLollipopLicker.h"

#define COUNT 20

@interface RMLollipopLicker ()

@property (weak, nonatomic) IBOutlet UIProgressView *progressView;

@property (weak, nonatomic) IBOutlet UILabel *label;

@property (weak, nonatomic) IBOutlet UILabel *lickedTimeLabel;

@end

@implementation RMLollipopLicker {

NSOperationQueue *queue;

NSMutableArray *lollipops;

}

#pragma mark - Life cycle

- (void)viewDidLoad {

[super viewDidLoad];

self.progressView.progress = 0.0;

self.label.text = [NSString stringWithFormat:@"Tap on run and I'll lick a lollipop %d times!", COUNT];

self.lickedTimeLabel.text = @"";

lollipops = [[NSMutableArray alloc] init];

queue = [[NSOperationQueue alloc] init];

}

- (void)lickLollipop {

NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"Lollipop" withExtension:@"plist"];

NSDictionary *dictionary = [NSDictionary dictionaryWithContentsOfURL:fileURL];

NSString *lollipop = [dictionary objectForKey:@"Lollipop"];

[lollipops addObject:lollipop];

}

#pragma mark - IBActions

- (IBAction)doneButtonPressed:(id)sender {

[self dismissViewControllerAnimated:YES completion:nil];

}

- (IBAction)runButtonPressed:(id)sender {

[sender setEnabled:NO];

[queue addOperationWithBlock:^{

for (NSInteger i = 0 ; i = COUNT) {

self.label.text = [NSString stringWithFormat:@"Tap on run and I'll lick a lollipop %d times!", COUNT];

self.progressView.progress = 0.0;

[sender setEnabled:YES];

}

}];

}

}];

}

@end

當用戶點擊運行按鈕, 應用開始一個背景線程,調(diào)用 lickLollipop 方法若干次,然后更新界面反映吃棒棒糖的數(shù)量。 lickLollipop 方法從屬性列表文件(PLIST)文件讀取一個長字符串,然后添加到數(shù)組上。這些數(shù)據(jù)并不重要, 能在不影響用戶體驗的前提下重新創(chuàng)建。

利用每種能夠清除和重建數(shù)據(jù)而不影響用戶體驗的情況是好習慣。這樣能夠方便地釋放內(nèi)存,減少低內(nèi)存警告。

那么,如何提高代碼質(zhì)量呢? 實現(xiàn) didReceiveMemoryWarning 方法,像下面這樣處理數(shù)據(jù):

-(void)didReceiveMemoryWarning {

[lollipops removeAllObjects];

[super didReceiveMemoryWarning];

}

搞定!

下一步?

萬歲,你研究了4個閃退案例! 你的應用更完善了,并且學到了一些重要的調(diào)試技巧。

你可以到 這里下載改進后的項目代碼。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 轉自http://www.raywenderlich.com/zh-hans/30818/ios應用崩潰日志揭秘 ...
    RunSnails閱讀 4,635評論 2 22
  • 出處:http://www.iteye.com轉自 http://www.raywenderlich.com/zh...
    中二修行者閱讀 925評論 0 0
  • 作為一名應用開發(fā)者,你是否有過如下經(jīng)歷?經(jīng)常被領導叫去,讓看哪位哪位客戶運行APP又崩潰了,感覺解決;天天被產(chǎn)品狗...
    繼續(xù)向前沖閱讀 2,995評論 0 9
  • 作為一名應用開發(fā)者,你是否有過如下經(jīng)歷? 為確保你的應用正確無誤,在將其提交到應用商店之前,你必定進行了大量的測試...
    姚姚先生閱讀 704評論 0 1
  • 8月7日作業(yè)雨完成情況 作業(yè):應交70人,實交70人(遲交3人)點評:應交70人,實交70人 各小組最佳文章 第一...
    HahnPRO閱讀 358評論 0 0

友情鏈接更多精彩內(nèi)容