- 小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
在日常开发中,循环引用是一个十分常见的问题。当两个不同的对象强持有对方的时候,就会导致两者都无法释放,就会有循环引用的问题。
今天就来聊聊如何用 Instruments Allocations 来检测循环引用。 在appdelegate中修改didFinishLaunchingWithOptions方法,将window的rootViewController改为rootViewController为ViewController的UINavigationController。
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
window?.rootViewController = UINavigationController(rootViewController: ViewController())
return true
}
之后简单的在ViewController中设置一个rightBarButtonItem,点击跳转到RedViewController。在RedViewController中,RedViewController持有service,而service也持有RedViewController,这样就形成了循环引用,导致两者都无法释放。
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Show Red", style: .plain, target: self, action: #selector(showRed))
}
@objc func showRed() {
navigationController?.pushViewController(RedViewController(), animated: true)
}
}
class Service{
var redController: RedViewController?
}
class RedViewController:UITableViewController {
deinit {
print("deinit")
}
let service = Service()
override func viewDidLoad() {
super.viewDidLoad()
tableView.backgroundColor = .red
service.redController = self
}
}
这里可以在Service弱引用redController来打破循环引用,这里要使用Instruments Allocations 检测循环引用,就不处理了。
打开Instruments Allocations,使用模拟器运行代码,然后不断的进入redController和退出redController,可以看到这里persistent 的个数一直在增长,个数等于进入redController的个数。
这里如果没有内存泄漏的话,个数应该一直是1的,接下来在Service中弱持有redController来看一下。Transient是 使用过的redController,每使用并释放 一个redController Transient都会增加1,并不是存在的redController个数