Pages

Wednesday, August 29, 2012

UIViewController purgeMemoryForReason and crashes in iOS App

測試 iPhone App 時候,最怕測出自己無法預料的問題。所謂無法預料的就是很難重製,但是它就這樣存在 App 上。而當我們用心就知道,一定有問題存在。當 App 用 Ad hoc 方式發佈出去,這些 App 都裝在夥伴們的 iPhone, iPad 上,當真正發生 Crash 了,真的會覺得很不安與莫名其妙不知道從何下手。

好的 Crash Report 平台 如 TestFlight, Crashlytics 等等。這些 Tool SDK 都還算好安裝,再利用它們在當 App Crash 後,
收集 Crash 的 Log 將它們送回平台上,再利用網頁的優勢來做統計,讓我們知道最後僅有線索記錄。

ISSUE UIKit-[UIViewController purgeMemoryForReason:]

終於收到問題的通知信件了,當收到這樣的標題再進去看內容,還真的讓人不解。因為現在手頭上開發的 App 已經採用 ARC (Automatic Reference Counting in Objective-C and Xcode) 的寫法了,所有的物件釋放時機都交給這個機制去運作,我都不用太擔心應該釋放時機點問題,怎麼會出現最後 Memory warning 才會出現狀況呢?

到網路上找尋大家經驗,在這則三則找到了問題主因:

主要問題所在,當 App 操作上難免會有記憶體上升,所以系統會發出低記憶體的警告 Notification。但是如果在 UIViewController 寫了 [[NSNotificationCenter defaultCenter] removeObserver:self] 如此一來會把 UIViewController 還要接收註冊的 Observer 也一帶 Release 掉,因此 UIViewController 就不會進入 didReceiveMemory,也跟著不會去釋放該要被釋放的物件,導致最後記憶體下不來,而最後整個 App 直接 Crash 收掉。


而會這樣寫法有兩個主因:
  1. 懶惰。
  2. 對於 NSNotificationCenter 了解深度不夠。

正確的寫法是像這樣 [[NSNotificationCenter defaultCenter] removeObserver:self name:NotificationName object:nil] 也就是自己註冊的 Observer 就一對一在 View 要被移除掉時候一起移除掉。這樣才不會將不屬於自己的 Observer 也被移除掉。

寫程式最怕的就是亂處理非屬於自己掌控自己建立的物件、指令,這樣整個邏輯都會亂掉。最佳寫法就是要低藕合,只處理屬於自己掌控的。對的寫法就不能偷懶。

1 comment:

  1. 說真的我看到這一篇才知道
    [[NSNotificationCenter defaultCenter] removeObserver:self]
    居然會把系統自己做的Notification也移掉呀! 感謝你了!
    但我覺得這感覺是apple的問題吶,像個陷阱,要碼加個參數,或者分開另個method處理,只這樣寫蠻容易理解成一次性方便地將自己所註冊的通知一併地移除掉而已。

    ReplyDelete