天天看點

iOS崩潰、異常---看的想睡覺(待續)

iOS崩潰、異常---看的想睡覺(待續) 為確定你的應用正确無誤,在将其送出到應用商店之前,你必定進行了大量的測試工作。它在你的裝置上也運作得很好,但是,上了應用商店後,還是有使用者抱怨會閃退 !   如果你跟我一樣是個完美主義者,你肯定想将應用做到盡善盡美。于是你打開代碼準備修複閃退的問題……但是,從何處着手呢?   這時iOS崩潰日志派上用場了。在大多數情況下,你能從中了解到關于閃退的詳盡、有用的資訊。   通過本教程,你将學習到一些常見的崩潰日志案例,以及如何從開發裝置和iTunes Connect上擷取崩潰日志檔案。你還将學習到符号化( symbolication),從日志追蹤到代碼 。你還将學習調試一個在待定情況下會閃退的應用。 什麼是崩潰日志,從哪裡能得它? iOS裝置上的應用閃退時,作業系統會生成一個崩潰報告,也叫崩潰日志,儲存在裝置上。   崩潰日志上有很多有用的資訊,包括應用是什麼情況下閃退的。通常,上面有每個正在執行線程的完整堆棧跟蹤資訊,是以你能從中了解到閃退發生時各線程都在做什麼,并分辨出閃退發生在哪個線程上。   有幾種方法可以從裝置上擷取崩潰日志。   裝置與電腦上的iTunes Store同步後,會将崩潰日志儲存在電腦上。根據電腦作業系統的不同,崩潰日志将儲存在以下位置: Mac OS X: ~/Library/Logs/CrashReporter/MobileDevice/   Windows XP:  C:Documents and Settings<USERNAME>Application DataApple ComputerLogsCrashReporterMobileDevice<DEVICE_NAME>   Windows Vista or 7:   C:Users<USERNAME>AppDataRoamingApple ComputerLogsCrashReporterMobileDevice<DEVICE_NAME>   當使用者抱怨閃退時,你可以要求他讓裝置與iTunes同步,并根據作業系統的不同,到上述位置把崩潰日志下載下傳下來,然後通過電子郵件發送給你。   你必需盡量擷取使用者裝置生成的所有崩潰日志。因為崩潰日志越多,就越容易診斷問題所在!   另外,如果你裝了Xcode,也能很容易通過Xcode從你的裝置上獲得崩潰日志。将iOS裝置連接配接到電腦上,然後打開Xcode。從菜單欄上選擇 Window  菜單, 然後選擇  Organizer (快捷方式是 Shift-CMD-2). 在 Organizer 視窗上, 選中  Devices 标簽欄. 在左側的導航面闆上,選中  Device Logs, 如下圖所示:

iOS崩潰、異常---看的想睡覺(待續)

  看看上圖,左側有好幾個 Device Logs 菜單項。  LIBRARY 下面的Device Logs是你所有裝置(曾經連接配接到Xcode的)的日志 。每個裝置下面的 Device Logs 是對應裝置的日志。   應用送出到App Store後,你也能從 iTunes Connect 擷取到使用者的崩潰日志. 登入到 iTunes Connect 上, 選擇  Manage Your Applications, 點選相應的應用, 點選應用圖示下面的  View Details 按鈕, 然後點選右欄Links部分的   Crash Reports 。

iOS崩潰、異常---看的想睡覺(待續)

如果沒有崩潰日志,試試點選Refresh 按鈕重新整理一下。如果你的應用還賣得不多,或者剛上架不久,iTunes Connect賬号上也可能還沒有任何崩潰日志。   如果iTunes Connect上有崩潰日志,你将看到如下圖:

iOS崩潰、異常---看的想睡覺(待續)

  有時,盡管有使用者報告閃退,你仍然看不到崩潰報告。這時,最好讓使用者直接把崩潰報告發送給你。   什麼情況下會産生崩潰日志? 兩種主要情況會産生崩潰日志: 1.應用違反作業系統規則。 2.應用中有Bug。   違反iOS規則包括在啟動、恢複、挂起、退出時watchdog逾時、使用者強制退出和低記憶體終止。讓我們詳細了解一下吧。   Watchdog 逾時機制 從iOS 4.x開始,退出應用時,應用不會立即終止,而是退到背景。 但是,如果你的應用響應不夠快,作業系統有可能會終止你的應用,并産生一個崩潰日志。這些事件與下列UIApplicationDelegate方法相對應: application:didFinishLaunchingWithOptions: applicationWillResignActive: applicationDidEnterBackground: applicationWillEnterForeground: applicationDidBecomeActive: applicationWillTerminate:   上面所有這些方法,應用隻有有限的時間去完成處理。如果花費時間太長,作業系統将終止應用。   注意: 如果你沒有把需要花費時間比較長的操作(如網絡通路)放在背景線程上就很容易發生這種情況。關于如果避免這種情況的資訊,請參考我們的另外兩篇教程: Grand Central Dispatch 和 NSOperations。   使用者強制退出 iOS 4.x開始支援多任務。如果應用阻塞界面并停止響應, 使用者可以通過在主螢幕上輕按兩下Home按鈕來終止應用。此時,操作應用将生成一個崩潰日志。   注意: 輕按兩下Home按鈕後,你将看到運作過的所有應用。那些應用不一定是正在運作,也不一定是被挂起。   通常,使用者點選Home按鈕時,應用将在背景保留約10分鐘,然後作業系統自動将其終止。 是以輕按兩下Home按鈕顯示的應用清單隻是表明那是一系列過去打開過的應用。删除那些應用的圖示不會産生任何崩潰日志。   低記憶體終止 子類化UIViewController時,你或許已經注意到didReceiveMemoryWarning方法。   在前台運作的應用擁有通路和使用記憶體的最高優化級。然而,這并不意味着該應用能使用裝置的所有可用記憶體 ——每個應用隻能使用一部分可用記憶體。   當記憶體使用達到一定程度時,作業系統将發出一個 UIApplicationDidReceiveMemoryWarningNotification 通知。同時,調用 didReceiveMemoryWarning 方法。   此時,為了讓應用繼續正常運作,作業系統開始終止在背景的其他應用以釋放一些記憶體。所有背景應用被終止後,如果你的應用還需要更多記憶體,作業系統會将你的應用也終止掉,并産生一個崩潰日志。而在這種情況下被終止的背景應用,不會産生崩潰日志。   注意: 根據 蘋果文檔, Xcode不會自動添加低記憶體日志。你必需手動擷取日志。 然而,根據我的個人經驗,使用 Xcode 4.5.2, 低記憶體日志也會自動導入,隻是”Process”和”Type”屬性都被标為Unknown(未知)。   另外,值得一提的是在極短時間内配置設定一大塊記憶體将給系統記憶體帶來巨大負擔。這樣,也會産生記憶體警告的通知。   應用中有Bug 如你所想,大多數閃退都是由于應用中有Bug,是以大多數崩潰日志的産生都是因為應用中的Bug。Bug的種類的有很多。   在本教程的後半部分,你将通過調試一個會産生崩潰日志的含有Bug的應用,學習如何找到問題所在并進行修複!   崩潰日志的執行個體 讓我們看看一個崩潰日志的執行個體,以使你在處理一些實際問題之前心裡有譜。   事不宜遲,見見你的新朋友吧:

iOS崩潰、異常---看的想睡覺(待續)

  這報告看起來像天書。:) 我們分幾部分來解讀吧:   (1) 程序資訊 第一部分是閃退程序的相關資訊。   Incident Identifier是崩潰報告的唯一辨別符。   CrashReporter Key 是與裝置辨別相對應的唯一鍵值。雖然它不是真正的裝置辨別符,但也是一個非常有用的情報:如果你看到100個崩潰日志的CrashReporter Key值都是相同的,或者隻有少數幾個不同的CrashReport值,說明這不是一個普遍的問題,隻發生在一個或少數幾個裝置上。   Hardware Model 辨別裝置類型。 如果很多崩潰日志都是來自相同的裝置類型,說明應用隻在某特定類型的裝置上有問題。上面的日志裡,崩潰日志産生的裝置是iPhone 4s。   Process 是應用名稱。中括号裡面的數字是閃退時應用的程序ID。   接下來幾行不言自明,無需贅述。   (2) 基本資訊 這部分給出了一些基本資訊,包括閃退發生的日期和時間,裝置的iOS版本。如果有很多崩潰日志都來自iOS 6.0,說明問題隻發生在iOS 6.0上。   (3) 異常 在這部分,你可以看到閃退發生時抛出的異常類型。還能看到異常編碼和抛出異常的線程。根據崩潰報告類型的不同,在這部分你還能看到一些另外的資訊。   (4) 線程回溯 這部分提供應用中所有線程的回溯日志。 回溯是閃退發生時所有活動幀清單。它包含閃退發生時調用函數的清單。看下面這行日志:

iOS崩潰、異常---看的想睡覺(待續)

  它包括四列: 幀編号—— 此處是2。 二進制庫的名稱 ——此處是 XYZLib. 調用方法的位址 ——此處是 0x34648e88. 第四列分為兩個子列,一個基本位址和一個偏移量。此處是0×83000 + 8740, 第一個數字指向檔案,第二個數字指向檔案中的代碼行。   (5) 線程狀态 這部分是閃退時寄存器中的值。一般不需要這部分的資訊,因為回溯部分的資訊已經足夠讓你找出問題所在。   (6) 二進制映像 這部分列出了閃退時已經加載的二進制檔案。   符号化Symbolication 第一次看到崩潰日志上的回溯時,你或許會覺得它沒什麼意義。我們習慣使用方法名和行數,而非像這樣的神秘位置:

iOS崩潰、異常---看的想睡覺(待續)

将這些十六進制位址轉化成方法名稱和行數的過程稱之為符号化。   從Xcode的Organizer視窗擷取崩潰日志後過幾秒鐘,崩潰日志将被自動符号化。上面那行被符号化後的版本如下 :

iOS崩潰、異常---看的想睡覺(待續)

Xcode符号化崩潰日志時,需要通路與App Store上對應的應用二進制檔案以及生成二進制檔案時産生的 .dSYM 檔案。必需完全比對才行。否則,日志将無法被完全符号化。   是以,保留每個分發給使用者的編譯版本非常重要。送出應用前進行歸檔時,Xcode将儲存應用的二進制檔案。可以在Xcode Organizer的Archives标簽欄下找到所有已歸檔的應用檔案。   在發現崩潰日志時,如果有相比對的.dSYM檔案和應用二進制檔案,Xcode會自動對崩潰日志進行符号化。如果你換到别的電腦或建立新的賬戶,務必将所有二進制檔案移動到正确的位置,使Xcode能找到它們。   ( 注意: 你必需同時保留應用二進制檔案和.dSYM檔案才能将崩潰日志完整符号化。每次送出到iTunes Connect的建構都必需歸檔。   .dSYM檔案和二進制檔案是特定綁定于每一次建構和後續建構的,即使來自相同的源代碼檔案,每一次建構也與其他建構不同,不能互相替換。   如果你使用Build 和 Archive 指令,這些檔案會自動放在适當位置。 如果不是使用Build 和 Archive指令,放在Spotlight能夠搜尋到的位置(比如Home目錄)即可。)   低記憶體閃退 因為低記憶體崩潰日志與普通崩潰日志略有不同,是以本教程特别分開說明一下。   iOS裝置檢測到低記憶體時,虛拟記憶體系統發出通知請求應用釋放記憶體。這些通知發送到所有正在運作的應用和程序,試圖收回一些記憶體。   如果記憶體使用依然居高不下,系統将會終止背景線程以緩解記憶體壓力。如果可用記憶體足夠,應用将能夠繼續運作而不會産生崩潰報告。否則,應用将被iOS終止,并産生低記憶體崩潰報告。   低記憶體崩潰日志上沒有應用線程的堆棧回溯。相反,上面顯示的是以記憶體頁數為機關的各程序記憶體使用量。(在撰寫本文的時候,一個記憶體頁的大小是4KB。)   被iOS因釋放記憶體頁終止的程序名稱後面你會看到jettisoned 字樣。如果看到它出現在你的應用名稱後面,說明你的應用因使用太多記憶體而被終止了。   低記憶體崩潰日志看起來像這樣:

iOS崩潰、異常---看的想睡覺(待續)

  當應用發生低記憶體閃退時,你必需看看應用中記憶體使用的方式,以及是如何處理低記憶體警告的。你可以使用Instruments工具中使用Allocations 和 Leaks來發現記憶體配置設定問題和記憶體洩漏問題。如果你不知道如何利用 Instruments 檢查記憶體問題,可以看看這個教程 。   還有,别忘記虛拟記憶體! Instruments工具的Leaks 和 Allocations 不能跟蹤顯存使用情況。必需使用 VM Tracker 才能檢視顯存使用情況。   VM Tracker 預設是關閉的。打開Instrument,手動 選中Automatic Snapshotting 标志或者按下Snapshot Now 按鈕。   本教程後面将會學習如何研究低記憶體崩潰日志。   異常編碼 在研究真實閃退場景之前,還有一點需要重點介紹一下:就是那些有趣的異常編碼 。   你可以在報告的異常部分——前面代碼的第3部分找到異常編碼。有些編碼比較常見。   通常,異常編碼以一些文字開頭,緊接着是一個或多個十六進制值,此數值正是說明閃退根本性質的所在。  從這些編碼中,可以區分出閃退是因為程式錯誤、非法記憶體通路或者是其他原因。 下面是一些常見的異常編碼:   0x8badf00d: 讀做 “ate bad food”! (把數字換成字母,是不是很像 :p)該編碼表示應用是因為發生watchdog逾時而被iOS終止的。  通常是應用花費太多時間而無法啟動、終止或響應用系統事件。

iOS崩潰、異常---看的想睡覺(待續)

0xbad22222: 該編碼表示 VoIP 應用因為過于頻繁重新開機而被終止。 0xdead10cc: 讀做 “dead lock”!該代碼表明應用因為在背景運作時占用系統資源,如通訊錄資料庫不釋放而被終止 。 0xdeadfa11: 讀做 “dead fall”! 該代碼表示應用是被使用者強制退出的。根據蘋果文檔, 強制退出發生在使用者長按開關按鈕直到出現 “滑動來關機”, 然後長按 Home按鈕。強制退出将産生 包含0xdeadfa11 異常編碼的崩潰日志, 因為大多數是強制退出是因為應用阻塞了界面。   ( 注意: 在背景任務清單中關閉已挂起的應用不會産生崩潰日志。 一旦應用被挂起,它何時被終止都是合理的。是以不會産生崩潰日志。)   大展身手的時候到了! 好了! 你已經學習了所有分析崩潰日志和修複錯誤的基礎知識!   假設你剛進入Rage-O-Rage有限公司工作。該公司有一個在App Store上熱銷的應用,叫  Rage Masters。   你的老闆安迪要你幫忙解決幾個使用者經常抱怨閃退問題。你的任務就是研究這些閃退,符号化使用者提供的崩潰日志,查找問題所在,并修複之。   你可以從 這裡下載下傳應用的源代碼。   ( 注意: 如果你想自己重新生成崩潰報告,請遵照以下指引: 1.下載下傳源碼然後在Xcode中打開工程檔案。 2.使用正确的provisioning profile連接配接到iOS裝置。 3.從Xcode工具欄上選擇iOS裝置——不是模拟器作為target,然後建構應用。 4.當你在裝置上到預設頁面(應用的全屏圖檔)時,立即在Xcode上點選停止按鈕。 5.關閉 Xcode。 6.在裝置上直接打開應用。 7.測試場景,完成後連接配接裝置到電腦上,通過Xcode擷取崩潰日志。)   場景 1: 糟糕的代碼 一封來自使用者的郵件: “大哥,你的應用就是一坨屎! 我将其下載下傳到我自己的iPod Touch和iPhone上,還下載下傳到我兒子的iPod Touch上。在所有的裝置上,都是還沒打開就閃退了……”   别一封來自使用者的郵件說, “我下載下傳了你們的應用,一打開就閃退。真悲催…”   另一封郵件說得更明确:”你們的應用不能運作。我把它下載下傳到我和妻子的裝置上。所有裝置都是 一打開就閃退了…”

iOS崩潰、異常---看的想睡覺(待續)

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

iOS崩潰、異常---看的想睡覺(待續)

  發現問題了嗎? 異常編碼是0x000000008badf00d,還有後面的報告:

iOS崩潰、異常---看的想睡覺(待續)

  這說明應用在啟動時就閃退了,iOS的watchdog機制終止了應用。帥! 找到問題了,但是為什會發生這樣的事呢?   接着往下看日志。 從下向上讀回溯日志。最底下的幀 (frame 25: libdyld.dylib)是最先調用的,然後是幀24, Rage Masters, main (main.m:16) ,依此類推。   跟應用源代碼相關的幀是最重要的。忽略掉系統庫和架構。下一個與代碼相關的幀是:

iOS崩潰、異常---看的想睡覺(待續)

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

iOS崩潰、異常---看的想睡覺(待續)

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

iOS崩潰、異常---看的想睡覺(待續)

Network calls on the main thread makes kittens sad.   不管如何,問題得你來修複了。這個調用必需異步進行,甚至更理想的情況是,在 application:didFinishLaunchingWithOptions:傳回YES之後的其他部分再執行Web服務。   在其他地方調用可能需要比較多的修改。當下,我們隻要使應用不閃退就行。可以在日後再實作更好的設計。 将上面那行讨厭的代碼(及其下面的三行代碼)換成下面這個異步的版本吧:

iOS崩潰、異常---看的想睡覺(待續)

    場景 2: 無法響應事件的按鈕 一名使用者說: “我不能将某個rage master添加到書簽裡面。我想添加的時候應用就閃退…”   用一名使用者說 :”書簽不能用 … 在詳細頁面上,點選書簽按鈕,應用就閃退了!”   上面的抱怨說得不是很清楚,引起問題的原因肯定有多樣。看看崩潰日志:

iOS崩潰、異常---看的想睡覺(待續)

  異常代碼是SIGABRT。通常,  SIGABRT 異常是由于某個對象接收到未實作的消息引起的。 或者,用簡單的話說,在某個對象上調用了不存在的方法。   這種情況一般不會發生,因為A對象調用了B方法,如果B方法不存在,編譯器會報錯。但是,如果你是使用selector間接調用方法的,編譯器則無法檢測對象是否存在該方法了。   回到崩潰日志。它指出閃退發生在編号為0的線程上。 這意味着很可能是在主線程上調用了某個對象沒有實作的方法。   如果你接着閱讀回溯日志,會發現跟你的代碼相關的隻有幀22, main.m:16. 這沒有多大幫助。    繼續向上檢視架構調用,出現這個:

iOS崩潰、異常---看的想睡覺(待續)

這不是你自己寫的代碼。但至少它确認了是對象調用了一個沒有實作的方法。   回到RMDetailViewController.m檔案, 因為那是書簽按鈕實作動作的地方。 找到書簽功能代碼:

iOS崩潰、異常---看的想睡覺(待續)

  看起來沒什麼問題,再檢查一下storyboard (XIB檔案) ,确認按鈕連接配接的正确性。

iOS崩潰、異常---看的想睡覺(待續)

就是它了! 在 MainStoryboard.storyboard,按鈕連接配接的是 bookmarkButtonPressed: 而不是bookmarkButtonPressed (注意後面的分号說明方法有一個參數)。 隻要将上面的方法簽名修改成這樣就能修複問題了:

iOS崩潰、異常---看的想睡覺(待續)

  當然,你也可以簡單地在XIB檔案上删除錯誤的連接配接,然後重新連接配接方法,使XIB檔案連接配接到正确的方法上。兩者方法都行。   又處理了一個閃退問題,好樣的。   場景 3: 表格上的Bug 另一使用者抱怨道, “在書簽視圖上無法删除書簽…” 還有另一使用者抱怨同樣的問題, “當我試圖删除書簽時,應用閃退…”   這些郵件沒什麼作用,還是看看崩潰日志!

iOS崩潰、異常---看的想睡覺(待續)

  這看起來跟前面那個崩潰日志很像。是另一個SIGABRT 異常。 你可能想知道是否是相同的問題:發送資訊到一個沒有實作相應方法的對象?   讓我們從回溯日志看看哪些方法被調用了。從底部開始,你的源代碼最後被調用的是幀 6:

iOS崩潰、異常---看的想睡覺(待續)

這是UITableViewDataSource 的一個方法. 呵呵?! 毫無疑問蘋果已經實作了該方法 —— 你可以重載它, 但不像是還沒有實作。而且,這是個可選的委派方法。 是以問題不是調用了一個沒有實作的方法。 再看看上面的幾個幀:

iOS崩潰、異常---看的想睡覺(待續)

  幀 5, UITableView調用了它自己的另一個方法 deleteRowsAtIndexPaths:withRowAnimation: 然後是看起來像蘋果内部方法的_endCellAnimationsWithContext: 被調用。然後Foundation framework發生異常handleFailureInMethod:object:file:lineNumber:description:.   這些分析結合使用者的抱怨,看起來是你在處理UITableView删除行過程中有Bug。回到Xcode。你知道看哪裡嗎 ? 能從崩潰日志中判斷出來? 就是RMBookmarksViewController.m檔案的第68行:

iOS崩潰、異常---看的想睡覺(待續)

  發現問題了嗎? 給你點時間,仔細看一下。   找到了吧! 資料源呢? 代碼在表格視圖上删除了一行,但并沒有修改背後的資料源。把上面的代碼替換成下面的就能修複問題了:

iOS崩潰、異常---看的想睡覺(待續)

  搞定了!走起,讨厭的 bug!!   場景 4: 吃棒棒糖時閃退! 使用者郵件說, “當rage master吃棒棒糖時應用就閃退…” 另一使用者說, “我讓rage master 吃棒棒糖,沒幾次應用就閃退了!”   崩潰日志如下:

iOS崩潰、異常---看的想睡覺(待續)
iOS崩潰、異常---看的想睡覺(待續)
iOS崩潰、異常---看的想睡覺(待續)

這日志跟我們前面見到的相差很多。   這個一個來自iOS 6的低記憶體崩潰日志。正如我們前面所說的,低記憶體崩潰日志與其他類型的崩潰日志很不一樣,它們不指向特定的檔案和代碼行。相反,它們畫出了閃退時裝置上的記憶體使用情況的圖表。   至少,頭部還是跟其他崩潰日志很像的:  提供了 Incident Identifier, CrashReporter Key, Hardware Model, OS Version等資訊。   接下來部分是低記憶體崩潰日志特有的: Free pages 指可用記憶體頁數。每頁大小約是4KB, 上面的日志中,可用記憶體約為3,872 KB (或者說 3.9 MB)。 Purgeable pages 是那部分可被清除或重用的記憶體。在上面的日志中,是0KB。 Largest process是閃退時使用大部分記憶體的應用名稱,在上面的日志中,正是你的應用! Processes顯示了閃退時各程序清單,還包含記憶體使用量。包含程序名 (第一列), 程序唯一辨別符(第二名), 程序使用的記憶體頁數(第三列)。最後一列是每個應用的狀态。通常,發生閃退的應用的狀态是 frontmost。 這裡是 Rage Masters, 使用28591 頁 (or 114.364 MB) 記憶體——這記憶體太多了!   通過,最大程序和frontmost狀态的應用是相同的, 而且也是引起低記憶體閃退的應用程序。但是也可能看到最大程序和 frontmost狀态應用不同的例子。比如,如果最大程序是SpringBoard, 忽略它 , 因為 SpringBoard 程序是顯示主螢幕的應用,出現在你輕按兩下home按鈕等情況,而且它是一直活動的。   低記憶體發生時,iOS向活動的應用發出低記憶體警告并終止背景應用。如果前台應用仍然繼續增長記憶體,iOS将終止它。   為了查找低記憶體問題的原因,你必需使用Instruments剖析應用。如果你不知道怎麼做,可以看一下我們 一篇關于這個方面的教程.。 :] 另外, 你也可以走捷徑,響應低記憶體警告通知,以解決部分閃退問題。 回到Xcode檢視RMLollipopLicker.m檔案。 這是實作吃棒棒糖的視圖控制器。看看源代碼:

iOS崩潰、異常---看的想睡覺(待續)

  當使用者點選運作按鈕, 應用開始一個背景線程,調用 lickLollipop 方法若幹次,然後更新界面反映吃棒棒糖的數量。 lickLollipop 方法從屬性清單檔案(PLIST)檔案讀取一個長字元串,然後添加到數組上。這些資料并不重要, 能在不影響使用者體驗的前提下重新建立。   利用每種能夠清除和重建資料而不影響使用者體驗的情況是好習慣。這樣能夠友善地釋放記憶體,減少低記憶體警告。   那麼,如何提高代碼品質呢? 實作 didReceiveMemoryWarning 方法,像下面這樣處理資料:

iOS崩潰、異常---看的想睡覺(待續)