SwiftUI视图任务和异步函数

thtygnil  于 2023-02-07  发布在  Swift
关注(0)|答案(1)|浏览(104)

我收到了一个关于这段代码的警告,我不知道如何修复它。我很想知道如何将一个函数传递到task修饰符中。

private func placeholderRHSView(for client: AppClient) -> some View {
    Color.clear
        .frame(width: 290, height: 290)
        .task(load(client)) // Warning: Converting non-sendable function value to '@Sendable () async -> Void' may introduce data races
}

private func load(_ client: AppClient) -> () -> Void {
    return {
        Task {
            do {
                let apps = try await client.recent()
            } catch {}
        }
    }
}

我应该如何重新构造这段代码以使其线程安全?

lp0sw83n

lp0sw83n1#

第一个问题是浮点Task {/*code*/}不是线程安全的,如果没有很好的理由和预防措施,就不应该使用它来模拟.task的生命周期行为。
现在,为了获得一个可以直接在.task中使用的函数,我们必须模拟签名

func task(priority: TaskPriority = .userInitiated, _ action: @escaping () async -> Void) -> some View

action() async -> Void,因此函数应返回确切的类型。您缺少async部分。
您还必须添加@Sendable,我们只从警告中了解到这一点

private func load(_ client: AppClient) -> (@Sendable () async -> Void) {

()意味着这将是一个闭包/函数,因此主体将用return {/*async code here*/}封闭

private func load(_ client: AppClient) -> (@Sendable () async -> Void) {
   return {
        do {
            let apps = try await client.recent()
            print(apps)
        } catch {
            print(error)
        }
    }
}

现在,View将按预期工作。

private func placeholderRHSView(for client: AppClient) -> some View {
    Color.clear
        .frame(width: 290, height: 290)
        .task(load(client))
}

我创建了一个小的mock AppClient来实现这个编译。

struct AppClient{
    func recent() async throws -> String{
        return "recent"
    }
}

相关问题