Swift:iOS 15 之前的任务 {}?

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

我正在按照教程来了解 SwiftUI,特别是如何在视图出现时调用 API。

我看到了这个:

List(results, id: \.trackId) { item in
    ListRow(item)
}
.task {
    // perform API here
}

但是由于我的应用程序面向 iOS 14,我收到此错误:

“任务(优先级:_:)”仅在 iOS 15.0 或更高版本中可用

那么我能做什么呢?谢谢你的帮助

swift swiftui task
5个回答
8
投票

您可以编写适用于 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()
            }
        }
    }
}

6
投票

仅仅切换到

.onAppear
是不正确的,因为它忽略了结构化并发的要点。每次您自己创建
Task
时,您都应该怀疑,您正在做一些不寻常的事情。

当然,在这种情况下,我们没有可用的“结构化并发感知”生命周期修饰符,因此我们需要使用

Task
init 创建自己的生命周期修饰符,但这意味着 您需要负责尊重结构化并发!

这意味着获得适当的向后兼容解决方案需要更多代码,因为您想要正确处理取消。为此,您还需要使用

.onDisappear
并取消您在
.onAppear
上开始的任务。

如果您想让它可重用,您可以制作自定义.task修饰符


5
投票

async await
适用于 iOS 13+。

https://developer.apple.com/documentation/swift/task

如果您需要使用

async
调用,请将调用包装在
Task

.onAppear(){
    Task{
        //Your async code here
        // await yourFuncHere()
    }
}     

.onAppear
有点不可靠,所以我可能会选择
init
ObservableObject
作为替代方案。


1
投票

没有一个被接受的答案很好地回答了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()
            }
    }
}

-1
投票
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 []
    }
}

编辑答案。

© www.soinside.com 2019 - 2024. All rights reserved.