【问题标题】:Recurring function in Swift 5.5 using async/awaitSwift 5.5 中使用 async/await 的循环函数
【发布时间】:2021-10-15 01:38:39
【问题描述】:

我想在函数完成 5 秒后继续触发它。

以前我会在函数末尾使用这个:

Timer.scheduledTimer(withTimeInterval: 5, repeats: false) { self.function() }

但我想使用Swift 5.5async/await

如果我使用这样的东西:

func loadInfo() async {
    async let info = someOtherAsyncFunc()
    self.info = try? await info
    await Task.sleep(5_000_000_000)
    await loadInfo()
}

我收到警告,Function call causes an infinite recursion 并不能真正取消。

这编译得很好:

func loadInfo() async {
    Task {
        async let info = someOtherAsyncFunc()
        self.info = try? await info
        await Task.sleep(5_000_000_000)
        if Task.isCancelled {
            print("Cancelled")
        }
        else
        {
            print("Not cancelled")
            await loadInfo()
        }
    }
}

虽然它每 5 秒触发一次,但当我的 SwiftUI 视图被关闭时它会继续运行。 我开始使用:

.onAppear {
    loadInfo()
}

因为它都在同一个Task 而不是detached 上运行,所以当视图被移除时它不应该全部取消吗?

使用async/await 实现这一目标的现代方法是什么?

【问题讨论】:

    标签: swift async-await swiftui swift5.5 swift-concurrency


    【解决方案1】:

    您可以将任务保存在@State 变量中,然后在视图消失时使用onDisappear(perform:) 取消它。

    工作示例:

    struct ContentView: View {
        @State private var info: String?
        @State private var currentTask: Task<Void, Never>?
    
        var body: some View {
            NavigationView {
                VStack {
                    Text(info ?? "None (yet)")
                        .onAppear(perform: loadInfo)
                        .onDisappear(perform: cancelTask)
    
                    NavigationLink("Other view") {
                        Text("Some other view")
                    }
                }
                .navigationTitle("Task Test")
            }
            .navigationViewStyle(.stack)
        }
    
        private func loadInfo() {
            currentTask = Task {
                async let info = someOtherAsyncFunc()
                self.info = try? await info
                await Task.sleep(5_000_000_000)
                guard !Task.isCancelled else { return }
                loadInfo()
            }
        }
    
        private func cancelTask() {
            print("Disappear")
            currentTask?.cancel()
        }
    
        private func someOtherAsyncFunc() async throws -> String {
            print("someOtherAsyncFunc ran")
            return "Random number: \(Int.random(in: 1 ... 100))"
        }
    }
    

    【讨论】:

    • 谢谢,太好了。我必须稍作修改才能使其编译。我需要使用.onAppear 而不是.task,因为loadInfo() 函数不是async
    • @Darren 谢谢,我现在已经改了。对我来说,它在 Xcode 13b3 上使用 .task(_:) 编译,但不是在 Xcode 13b5 上编译。
    猜你喜欢
    • 2019-07-16
    • 1970-01-01
    • 2021-09-19
    • 2016-12-30
    • 2021-10-02
    • 1970-01-01
    • 2021-07-26
    • 2022-01-03
    • 2017-04-29
    相关资源
    最近更新 更多