1.问题
你知道delegate 如果是strong 修饰的话,就会引起循环引用。导致内存释放不掉,内存泄漏。
你知道 :block 里,如果 用到 self 的话,就必须 先weak self ,如果不用的话就会导致内存释放不掉,内存泄漏。
但是 你知道 究竟怎么样 才能检测到循环引用 引起的内存泄漏吗?
怎么看我的代码究竟有没有 内存泄漏?
2 代码
下面我们就用Instrument 检测下 循环引用。更直观的感受下。
内存检测代码:
LeakController 里 调用 LeakImageView 显示图片。并设置 LeakImageView 的delegate, 注意 LeakImageView 的delegate 并未用weak 引用。会引起循环 应用。
LeakController 预览
LeakController 代码
//
// LeakController.swift
// Cycle
//
// Created by Sunny on 2017/9/29.
// Copyright © 2017年 Sunny. All rights reserved.
// 简书: //www.greatytc.com/u/2dc174d83679
import UIKit
class LeakController: UIViewController {
@IBOutlet weak var leakImageView: LeakImageView!
override func viewDidLoad() {
super.viewDidLoad()
// 循环引用 代码
leakImageView.delegate = self //注销 此句 代码 可以 执行deinit, 否则不执行deinit
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
deinit {
print("释放 LeakController")
}
}
LeakImageView 预览
LeakImageView 代码
//
// LeakImageView.swift
// Cycle
//
// Created by Sunny on 2017/9/29.
// Copyright © 2017年 Sunny. All rights reserved.
// 简书: //www.greatytc.com/u/2dc174d83679
import UIKit
class LeakImageView: UIImageView {
/// delegate 强引用 ,delegate 的实现方式就在此省去。
var delegate : AnyObject? ;
deinit {
print("释放 leakImageView")
}
}
准备工作已做好,现在开始检测
3.检测
循环引用是 因为不能释放掉ViewController ,所以永远不会执行 LeakController里的 “deinit” 方法
(1).instrument 启动 选择APP ,并选择Allocations。
(2).查看 Persistent (持久内存)
会发现Persistent 会从 0 一直涨。而且不减。我跳转了11次,此处就显示11。说明 现在存活的LeakController 为 11 个。但是 正常应该是显示 1 个。
循环引用的Persistent (如下图)
注意左下角可以 筛选项目的类,输入 《项目名称》即可筛选项目类
正常的Persistent (如下图)
Transient(短暂的,路过的) 是 使用过的LeakController;每使用并释放 一个Leakcontroller Transient都会增加1. 这个才是正常的。
总结:
不断的跳转,并返回时: 循环引用时 Persistent 会一直增长.; 且不会调用 deinit 方法。
正常情况下 Persistent 是正常使用的个数,本项目里是1.且会调用deinit 方法。