做者:Thomas Hanning,原文連接,原文日期:2015-11-09
譯者:靛青K;校對:littledogboy;定稿:shanksswift
儘管 ARC 已經爲咱們作了大部份內存管理的事情,但你的 App 仍然可能遇到循環引用的問題。所以發現這些潛在的循環引用是很是重要的。ide
隨着在 iOS 5 中 介紹的自動引用計數(ARC)的使用,內存管理變得很是簡單。但 ARC 不能處理全部狀況,因此處理好 App(應用程序) 的內存管理仍是很是重要的。例如,可能存在所謂的循環引用。就好比在應用程序中儘管沒有任何可訪問的引用指向視圖控制器,但視圖控制器也沒有被銷燬。若是存在這種循環引用,那麼每次出現這個視圖控制器,應用程序的內存都會增長。若是內存不停地增長,App 會被操做系統終止 —— App 崩潰。工具
咱們來建立一個循環引用的例子:首先,咱們建立了一個 RootViewController
和一個 SecondViewController
。當點擊 RootViewController
的一個按鈕後,就出現 (present
)一個 SecondViewController
。你能夠在 storyboard 中經過 segue 輕鬆建立。 另外,再建立一個 ModelObject
類,該類中有一個類型爲 ModelObjectDelegate
的 delegate 實例變量 。當 SecondViewController
加載完視圖後,把 ModelObject
的代理設置爲self
。ui
import Foundation protocol ModelObjectDelegate: class { } class ModelObject { var delegate: ModelObjectDelegate? } import UIKit class SecondViewController: UIViewController, ModelObjectDelegate { var modelObject: ModelObject? override func viewDidLoad() { super.viewDidLoad() modelObject = ModelObject() modelObject!.delegate = self } @IBAction func closeButtonPressed(sender: UIButton) { dismissViewControllerAnimated(true, completion: nil) } }
好的,如今咱們來檢查一下內存管理:當咱們移除SecondViewController
時,內存並不會減小。但這是爲何呢?
咱們預期的結果是移除時,SecondViewController
內存就會銷燬。咱們來看一下這些對象。當SecondViewController
加載後,引用狀況是下圖這個樣子:spa
如今,當移除SecondViewController
時,引用狀況是這個樣子:操作系統
RootViewController
取消了強引用 SecondViewController
。然而 SecondViewController
和 ModelObject
互相強引用。所以它們都沒有被銷燬。翻譯
發現循環引用的技巧以下所示: 代理
若是一個對象被銷燬,會執行對應的 deinit
方法。因此只須要在類中的 deinit
方法中添加一個打印信息:調試
import UIKit class SecondViewController: UIViewController, ModelObjectDelegate { var modelObject: ModelObject? override func viewDidLoad() { super.viewDidLoad() modelObject = ModelObject() modelObject!.delegate = self } @IBAction func closeButtonPressed(sender: UIButton) { dismissViewControllerAnimated(true, completion: nil) } deinit { print("SecondViewController deinit") } } import Foundation protocol ModelObjectDelegate: class { } class ModelObject { var delegate: ModelObjectDelegate? deinit { print("ModelObject deinit") } }
當咱們移除 SecondViewController
,調試窗口並無日誌信息。也就是說他們並無被銷燬,說明出了些問題。日誌
咱們已經知道這裏多了一個強引用。因此咱們能夠聲明delegate
爲weak
屬性。
import Foundation protocol ModelObjectDelegate: class { } class ModelObject { weak var delegate: ModelObjectDelegate? deinit { print("ModelObject deinit") } }
如今的對象關係是這個樣子:
由於 SecondViewController
和 ModelObject
之間僅有一個強引用,這裏應該不會再有什麼問題了。
沒錯,如今當咱們移除SecondViewController
調試窗口會有日誌信息了:
SecondViewController deinit ModelObject deinit
如今和咱們的預期狀況同樣了。
儘管這是一點點的工做,爲了發現循環引用應該在視圖控制器的deinit
方法中添加一條日誌信息。你也可使用 Instruments(Xcode自帶的內存檢測工具) 發現循環引用,但若是老是把日誌信息放在deinit
方法中,能夠持續監測銷燬行爲了。
本文由 SwiftGG 翻譯組翻譯,已經得到做者翻譯受權,最新文章請訪問 http://swift.gg。