You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Xcode Visual Memory Debugger排查lazy视图关闭VC后未释放问题

问题原因与修复方案

lazy var 本身不会导致对象无法释放,延迟初始化语法和内存泄漏没有关联,当前代码存在明确的强引用链异常,属于代码编写错误,具体问题点如下:

  • 跨父视图层级的强引用残留
    你在 HeadeViewMenu 中将外部传入的 tabBarController.view 强引用为自身属性,同时将内部的 tabBarView 直接添加到了这个属于全局根层级的视图上:
    // 错误点1:强引用不属于自身层级的父视图
    var tabBar: UIView!
    
    func setupTabBar(view: UIView) {
        guard tabBarHeight != nil else { return }
        tabBar = view // 这里对传入的tabBarController.view是强持有
        tabBar.addSubview(tabBarView) // UIKit中父视图会强持有所有子视图
        // 省略约束代码
    }
    
    调用时传入的 (self.tabBarController?.view)! 是被根控制器全局持有的视图,不会随业务VC销毁。你的 tabBarView 被这个全局视图强持有,就算业务VC执行pop/dismiss操作销毁,这条引用链也不会断开,最终导致 HeadeViewMenu 连同内部的 HeaderMenuCell、UITableView 等子对象都无法被释放。
  • 销毁判断逻辑错误
    1. 你在 viewDidDisappear 中手动置空delegate是无效操作:首先delegate本身已经声明为weak,本来就不会产生循环引用;其次viewDidDisappear仅代表视图离开屏幕,不代表VC被销毁(比如push切换页面时也会触发该方法)。
    2. 仅通过内存图谱看到对象存在不能直接判定为内存泄漏:内存图谱存在已释放对象的缓存残留可能,判断是否释放的金标准是看对应类的deinit方法是否执行——你已经在HeadeViewMenu中写了deinit打印,持有该视图的VC也可以添加deinit打印,返回根控制器后如果两个deinit日志都正常打印,就说明对象已经被正常回收。
  • 其他易忽略的引用问题
    你代码中所有闭包内使用self目前没有循环引用问题(UIView动画闭包不会强持有self),UITableView的delegate/dataSource在iOS9之后已经是weak声明,不会因为tableView持有self产生循环引用。

修复步骤

  1. 将HeadeViewMenu中的tabBar属性改为弱引用:
    // 原代码 var tabBar: UIView!
    weak var tabBar: UIView?
    
  2. 在持有P_headerViewNewMenu的VC的deinit方法中,手动将跨层级添加的tabBarView从父视图移除:
    deinit {
        P_headerViewNewMenu.tabBarView.removeFromSuperview()
        print("VC deinit called")
    }
    
  3. 删除viewDidDisappear中置空delegate的无效代码,该操作没有实际作用。
  4. 验证:返回根控制器后,查看控制台是否打印VC和HeadeViewMenu的deinit日志,正常打印即代表内存释放正常。

内存图谱截图

内容的提问来源于stack exchange,提问作者Ice

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 13:19:06