1.問(wèn)題
你知道delegate 如果是strong 修飾的話,就會(huì)引起循環(huán)引用。導(dǎo)致內(nèi)存釋放不掉,內(nèi)存泄漏。
你知道 :block 里,如果 用到 self 的話,就必須 先weak self ,如果不用的話就會(huì)導(dǎo)致內(nèi)存釋放不掉,內(nèi)存泄漏。
但是 你知道 究竟怎么樣 才能檢測(cè)到循環(huán)引用 引起的內(nèi)存泄漏嗎?
怎么看我的代碼究竟有沒(méi)有 內(nèi)存泄漏?
2 代碼
下面我們就用Instrument 檢測(cè)下 循環(huán)引用。更直觀的感受下。
內(nèi)存檢測(cè)代碼:
LeakController 里 調(diào)用 LeakImageView 顯示圖片。并設(shè)置 LeakImageView 的delegate, 注意 LeakImageView 的delegate 并未用weak 引用。會(huì)引起循環(huán) 應(yīng)用。
LeakController 預(yù)覽
LeakController 代碼
//
// LeakController.swift
// Cycle
//
// Created by Sunny on 2017/9/29.
// Copyright ? 2017年 Sunny. All rights reserved.
// 簡(jiǎn)書: http://www.lxweimin.com/u/2dc174d83679
import UIKit
class LeakController: UIViewController {
@IBOutlet weak var leakImageView: LeakImageView!
override func viewDidLoad() {
super.viewDidLoad()
// 循環(huán)引用 代碼
leakImageView.delegate = self //注銷 此句 代碼 可以 執(zhí)行deinit, 否則不執(zhí)行deinit
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
deinit {
print("釋放 LeakController")
}
}
LeakImageView 預(yù)覽
LeakImageView 代碼
//
// LeakImageView.swift
// Cycle
//
// Created by Sunny on 2017/9/29.
// Copyright ? 2017年 Sunny. All rights reserved.
// 簡(jiǎn)書: http://www.lxweimin.com/u/2dc174d83679
import UIKit
class LeakImageView: UIImageView {
/// delegate 強(qiáng)引用 ,delegate 的實(shí)現(xiàn)方式就在此省去。
var delegate : AnyObject? ;
deinit {
print("釋放 leakImageView")
}
}
準(zhǔn)備工作已做好,現(xiàn)在開(kāi)始檢測(cè)
3.檢測(cè)
循環(huán)引用是 因?yàn)椴荒茚尫诺鬡iewController ,所以永遠(yuǎn)不會(huì)執(zhí)行 LeakController里的 “deinit” 方法
(1).instrument 啟動(dòng) 選擇APP ,并選擇Allocations。
(2).查看 Persistent (持久內(nèi)存)
會(huì)發(fā)現(xiàn)Persistent 會(huì)從 0 一直漲。而且不減。我跳轉(zhuǎn)了11次,此處就顯示11。說(shuō)明 現(xiàn)在存活的LeakController 為 11 個(gè)。但是 正常應(yīng)該是顯示 1 個(gè)。
循環(huán)引用的Persistent (如下圖)
注意左下角可以 篩選項(xiàng)目的類,輸入 《項(xiàng)目名稱》即可篩選項(xiàng)目類
正常的Persistent (如下圖)
Transient(短暫的,路過(guò)的) 是 使用過(guò)的LeakController;每使用并釋放 一個(gè)Leakcontroller Transient都會(huì)增加1. 這個(gè)才是正常的。
總結(jié):
不斷的跳轉(zhuǎn),并返回時(shí): 循環(huán)引用時(shí) Persistent 會(huì)一直增長(zhǎng).; 且不會(huì)調(diào)用 deinit 方法。
正常情況下 Persistent 是正常使用的個(gè)數(shù),本項(xiàng)目里是1.且會(huì)調(diào)用deinit 方法。