使用Instruments Allocations 检测循环引用

578 阅读1分钟

在日常开发中,循环引用是一个十分常见的问题。当两个不同的对象强持有对方的时候,就会导致两者都无法释放,就会有循环引用的问题。

在这里插入图片描述

今天就来聊聊如何用 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个数

在这里插入图片描述