异步函数Swift和Combine的最佳实践

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

我正在将我的 Swift 应用程序转换为使用组合以及

async/await
,并且我试图了解处理异步函数和主线程之间交互的最佳方法是什么。

这是一个加载用户的异步函数:

class AccountManager {

    static func fetchOrLoadUser() async throws -> AppUser {
        if let user = AppUser.current.value {
            return user
        }
    
        let syncUser = try await loadUser()
        let user = try AppUser(syncUser: syncUser)
    
        AppUser.current.value = user // [warning]: "Publishing changes from background threads is not allowed"
        return user
    }
}

还有一堂课:

class AppUser {

    static var current = CurrentValueSubject<AppUser?,Never>(nil)

    // ...
}

注意:我选择使用

CurrentValueSubject
,因为它允许我 (1) 在需要时同步读取该值,以及 (2) 订阅更改。

现在,在上面标记的行上我收到错误

Publishing changes from background threads is not allowed
,我明白了。我看到了解决这个问题的不同方法:

1.将整个
AccountManager
类标记为
@MainActor

由于异步函数中完成的大部分工作都是等待网络结果,我想知道简单地在主线程上运行所有内容是否存在问题。这是否会导致性能问题?

2. Englobe 错误线位于
DispatchQueue.main.sync

这是一个合理的解决方案,还是会导致死锁等线程问题?

3.将
DispatchGroup
enter()
leave()
wait()

一起使用

就像这个答案。与解决方案#2 有什么区别吗?因为这个解决方案需要更多的代码行,所以如果可能的话我宁愿不使用它——我更喜欢干净的代码。

swift concurrency combine
1个回答
1
投票

您可以将呼叫包装在

await MainActor.run { }
块中。我认为这是最快捷的方法。

在使用 Swift Concurrency 时不应该使用 Dispatch 机制,尽管我认为

DispatchQueue.main.async { }
在这里可以安全使用。

@MainActor
属性是安全的,但不应该在
ObservableObject
上使用,并且如果 CPU 绑定代码在带注释类型的方法中运行,则可能会降低 UI 速度。

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