swift 接收ObservedObject上的异步数据

velaa5lx  于 2023-01-12  发布在  Swift
关注(0)|答案(1)|浏览(128)

我正在尝试构建一个Singleton ApiManager类,它可以为我构建和发送所有API请求,并将响应数据发送到等待请求的对象。在SwiftUI中,当我看到,假设用户成功登录,我想把视图切换到一个 Jmeter 板,问题是我使用ObservableObject来发布"isLoggedIn"布尔值,并且我在后台线程上发出所有的后端请求。我收到此错误

  • [SwiftUI]不允许从后台线程发布更改;确保在模型更新时从主线程发布值(通过receive(on:)等操作符)。*

下面是执行API请求的方法

func performRequest(with request: some AbstractRequest) {
    var link = host + request.endpoint
    appendParameters(to: &link, with: request.params)
    
    guard let url = URL(string: link) else {
        print("Failed to generate url from \(link)")
        return
    }
    
    let task = URLSession.shared.dataTask(with: url){ data, response, error in
        guard let data = data, error == nil else{
            print("\(error?.localizedDescription ?? "")")
            return
        }
        request.completion(data: data)
    }
    task.resume()
}

下面是一个示例完成处理程序(如果您能告诉我为什么会收到此警告,则会加分

    • 从"[LoginResponse]"到"[LoginResponse]"的条件强制转换始终成功**

在石膏线上,但如果我取下石膏,它会抱怨。)

func completion(data: Data)
{
    do{
        guard let response = try JSONDecoder().decode([LoginResponse].self, from: data) as? [LoginResponse] else { return }
        delegate.responseReceived(response: response)
    }catch let error{
        print("\(error.localizedDescription)")
    }
}

下面是我的LoginManager的外观

class LoginManager: ObservableObject, ApiRequestDelegate{
    static var shared = LoginManager()
    
    var token = ""
    @Published var isLoggedIn: Bool = false
    
    func responseReceived(response: Any) {
        guard let response = response as? LoginResponse, response.token != -1 else { return }
        token = String(response.token)
        isLoggedIn = true
    }
}

最后是我的内容视图

struct ContentView: View {
    @ObservedObject var loginManager = LoginManager.shared
    var body: some View {
        if !loginManager.isLoggedIn {
            LoginView()
        }else {
            OpenLinkButton().ignoresSafeArea()
        }
    }
}
xxhby3vn

xxhby3vn1#

URLSession.shared.dataTask中的完成处理程序是在后台线程上调用的,因此后面的所有操作都在后台线程上执行。
最简单的解决方案是将UI更改分派给主线程。例如:

DispatchQueue.main.async{
    isLoggedIn = true
}

另一种解决方案是用@MainActor属性来修饰与UI交互的函数,例如:

@MainActor
func responseReceived(response: Any) {

相关问题