为什么当视图消失时任务不会自动取消?

问题描述 投票:0回答:1

根据 Apple 文档,当视图消失时任务将自动取消。

SwiftUI 会在任务结束后的某个时刻自动取消任务 视图在操作完成之前消失。

为什么在这种情况下,当ChildView消失时,'loadData'方法中的Task没有被取消? (当导航回“ParentView”时)

struct ChildView: View {
    
    @State private var data: [Double] = []
    
    private func loadData() async {
        // Why isn't this Task automatically cancelled when the ChildView disappears?
        // The Task is still executing in the background.
        Task(priority: .background) {
            // Simulating heavy data processing.
            self.data = (1...3_000_000).map { _ in Double.random(in: -10...30) }
            print("Task ended")
        }
    }
    
    var body: some View {
        Text("This is a child view")
            .task { await loadData() }
    }
}

struct ParentView: View {
    var body: some View {
        NavigationStack {
            NavigationLink(destination: { ChildView() }) {
                Text("Show child view")
            }
        }
    }
}

即使 ChildView 消失,“loadData”中的任务也会继续执行。当ChildView连续多次初始化时也会执行多次。

这可能会导致内存泄漏,尤其是在 ChildView 中使用具有 @Published 'data' 属性而不是 @State 属性的类时。在这种情况下使用 Task() 的正确实现是什么?

swift swiftui async-await task
1个回答
0
投票

SwiftUI 确实取消了由

task
视图修饰符隐式创建的任务,但该任务不执行“繁重的数据处理”。该任务仅创建一个子任务来运行
loadData
。该子任务几乎立即完成。

这是因为

loadData
所做的只是通过使用 Task { ... } 创建一个
顶级任务
,而不执行其他任何操作。当您的视图消失时,
loadData
任务就已经完成了。然而,顶级任务执行所有“繁重的数据处理”,并且因为它是顶级任务(即不是
loadData
任务的子任务),所以当
loadData
被取消时,它不会被取消.

您不应该在此处创建顶级任务。把繁重的数据处理直接放在

loadData

此外,任务取消是合作性的 -

loadData
还应该检查
Task.isCancelled
并停止正在执行的操作。

private func loadData() async {
    for _ in 1...3_000_000 {
        if Task.isCancelled { // for example
            break
        }
        self.data.append(Double.random(in: -10..<30))
    }
    print("Task ended")
}
© www.soinside.com 2019 - 2024. All rights reserved.