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

SwiftUI中绑定Sheet的Item未销毁引发循环引用问题

问题分析

循环引用的核心原因是闭包的强引用链:

  • 创建Item实例时,传入的闭包{ item = nil }会捕获ContentView的实例(因为item是ContentView的@State属性)。
  • Item实例持有该闭包,而ContentView又通过@State var item持有Item实例,形成ContentView → Item → 闭包 → ContentView的循环引用,导致Item的deinit永远无法触发。
解决方案

方案1:给闭包添加弱引用捕获

修改ContentView中创建Item的代码,通过[weak self]让闭包弱引用ContentView,打破强引用链:

Button("Show") {
    item = Item { [weak self] in
        self?.item = nil
    }
}

这样当item被设为nil时,Item实例不再被强引用,就能正常触发deinit。

方案2:利用SwiftUI环境dismiss,彻底消除闭包传递

遵循SwiftUI的设计理念,不用手动传递dismiss闭包,直接在子视图中使用@Environment(\.dismiss)来关闭Sheet:

class Item: Identifiable {
    init() {
        print("init >> item \(Unmanaged.passUnretained(self).toOpaque())")
    }

    deinit {
        print("deinit >> item \(Unmanaged.passUnretained(self).toOpaque())")
    }

    func start() -> some View {
        ViewTwo()
    }
}

struct ContentView: View {
    @State private var item: Item? {
        didSet {
            print(item)
        }
    }

    var body: some View {
        Button("Show") {
            item = Item()
        }
        .sheet(item: $item) { item in
            item.start()
        }
    }
}

struct ViewTwo: View {
    @Environment(\.dismiss) private var dismiss

    var body: some View {
        VStack {
            Button("Dismiss") {
                dismiss()
            }
        }
    }
}

这种方式从根源上避免了闭包引用带来的循环问题,代码更简洁也更符合SwiftUI的范式。

方案3:将Item的dismiss改为可选类型(保留闭包传递场景)

如果业务必须保留闭包传递,可以将Item中的dismiss设为可选类型,并在deinit中置空,配合弱引用捕获使用:

class Item: Identifiable {
    var dismiss: (() -> Void)?

    init(dismiss: @escaping () -> Void) {
        self.dismiss = dismiss
        print("init >> item \(Unmanaged.passUnretained(self).toOpaque())")
    }

    deinit {
        print("deinit >> item \(Unmanaged.passUnretained(self).toOpaque())")
        dismiss = nil
    }

    func start() -> some View {
        ViewTwo(dismiss: dismiss!)
    }
}

// 创建Item时仍需添加弱引用捕获
Button("Show") {
    item = Item { [weak self] in
        self?.item = nil
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 15:47:32