我正在按照教程来了解 SwiftUI,特别是如何在视图出现时调用 API。
我看到了这个:
List(results, id: \.trackId) { item in
ListRow(item)
}
.task {
// perform API here
}
但是由于我的应用程序面向 iOS 14,我收到此错误:
“任务(优先级:_:)”仅在 iOS 15.0 或更高版本中可用
那么我能做什么呢?谢谢你的帮助
您可以编写适用于 iOS 13、iOS 14 的
task { }
版本,并使用适用于 iOS 15 的苹果版本:
extension View {
@available(iOS, deprecated: 15.0, message: "This extension is no longer necessary. Use API built into SDK")
func task(priority: TaskPriority = .userInitiated, _ action: @escaping @Sendable () async -> Void) -> some View {
self.onAppear {
Task(priority: priority) {
await action()
}
}
}
}
仅仅切换到
.onAppear
是不正确的,因为它忽略了结构化并发的要点。每次您自己创建Task
时,您都应该怀疑,您正在做一些不寻常的事情。
当然,在这种情况下,我们没有可用的“结构化并发感知”生命周期修饰符,因此我们需要使用
Task
init 创建自己的生命周期修饰符,但这意味着 您需要负责尊重结构化并发!
这意味着获得适当的向后兼容解决方案需要更多代码,因为您想要正确处理取消。为此,您还需要使用
.onDisappear
并取消您在 .onAppear
上开始的任务。
如果您想让它可重用,您可以制作自定义.task修饰符。
async await
适用于 iOS 13+。
https://developer.apple.com/documentation/swift/task
如果您需要使用
async
调用,请将调用包装在 Task
中
.onAppear(){
Task{
//Your async code here
// await yourFuncHere()
}
}
.onAppear
有点不可靠,所以我可能会选择 init
的 ObservableObject
作为替代方案。
没有一个被接受的答案很好地回答了OP的问题。创建一个传播回
.task
的 .onDisappear
修改器并取消它。这是完整的代码,可让您在任何 iOS/macOS 版本上使用 .task
(此处的最佳答案不处理取消任务)。
struct TaskModifier: ViewModifier {
let priority: TaskPriority
let action: @Sendable () async -> Void
@State var task: Task<Void, Never>? = nil
func body(content: Content) -> some View {
content
.onAppear {
if task != nil {
task?.cancel()
}
task = Task(priority: priority, operation: action)
}
.onDisappear {
task?.cancel()
}
}
}
extension View {
@available(iOS, deprecated: 15.0)
func task(priority: TaskPriority = .userInitiated, _ action: @escaping @Sendable () async -> Void) -> some View {
self.modifier(TaskModifier(priority: priority, action: action))
}
}
然后使用,像内置的一样使用
.task
:
struct Example: View {
var body: some View {
Text("Hello World")
.task {
await someAsyncFunc()
}
}
}
import SwiftUI
struct TaskEntry: Identifiable {
let id = UUID()
let title: String
// Add other properties if needed
}
struct ContentView: View {
@State var results = [TaskEntry]()
@State private var dataTask: Task<Void, Error>?
var body: some View {
List(results, id: \.id) { item in
VStack(alignment: .leading) {
Text(item.title)
}
}
.onAppear {
dataTask = Task {
do {
results = try await loadData()
} catch {
print("Error loading data: \(error.localizedDescription)")
// Handle error accordingly
}
}
}
.onDisappear {
dataTask?.cancel()
}
}
func loadData() async throws -> [TaskEntry] {
// Simulated asynchronous data fetching
// Replace this with your actual data fetching logic
// For now, returning an empty array as a placeholder
return []
}
}
编辑答案。