Swift 5.5中使用async/await的循环函数



我想在函数完成后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实现这一目标的现代方法是什么?

您可以将任务保存在@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))"
}
}

async await的目的是让您以同步的方式编写异步代码。因此,您可以删除递归函数并简单地写入:

.task {
repeat {
// code you want to repeat
print("Tick")
try? await Task.sleep(for: .seconds(5)) // exception thrown when cancelled by SwiftUI when this view disappears.
} while (!Task.isCancelled)
print("Cancelled")  
}

我注意到print tick总是在主线程上,但是如果我把它移到它自己的async函数中,那么它就会正确地在不同的线程上运行。

相关内容

  • 没有找到相关文章

最新更新