如何从后台线程 Swift UI GET 请求发布更改
Posted
技术标签:
【中文标题】如何从后台线程 Swift UI GET 请求发布更改【英文标题】:How to publish changes from the background thread Swift UI GET Request 【发布时间】:2020-06-09 19:44:39 【问题描述】:我已经设置了我的应用程序,以便我使用 UserDefaults 来存储用户登录信息(isLoggedIn,帐户设置)。如果用户登录并退出应用程序,然后重新启动应用程序,我希望他们返回到主页选项卡。
此功能有效;但是,由于某种原因,在重新启动主页时应该执行 getRequest。相反,屏幕变白。当我从登录名导航时,此请求和所涉及的加载有效,但在我重新启动应用程序时无效。我收到此警告:
Publishing changes from background threads is not allowed; make sure to publish values from the main thread (via operators like receive(on:)) on model updates.
在查看其他堆栈溢出帖子时,普遍的看法似乎是将任何类型的更改包装在 dispatchqueue.main.async 中;但是,这似乎对我不起作用。
import SwiftUI
struct StoresView: View
@ObservedObject var request = Request()
@Environment(\.imageCache) var cache: ImageCache
@EnvironmentObject var carts: Carts
init()
getStores()
var body: some View
NavigationView
List(self.request.stores) store in
NavigationLink(destination: CategoryHome(store: store).environmentObject(self.carts))
VStack(alignment: .leading)
Text(store.storeName)
.font(.system(size: 20))
.navigationBarTitle(Text("Stores").foregroundColor(Color.black))
func getStores()
DispatchQueue.main.async
self.request.getStoresList() stores, status in
if stores != nil
self.request.stores = stores!
在 Request 类中获取 store 调用
class Request: ObservableObject
@Published var stores = [Store]()
let rest = RestManager()
func getStoresList(completionHandler: @escaping ([Store]?, Int?)-> Void)
guard let url = URL(string: "@@@@@@@@@@@@@@@@@@@") else return
self.rest.makeRequest(toURL: url, withHttpMethod: .GET, useSessionCookie: false) (results) in
guard let response = results.response else return
if response.httpStatusCode == 200
guard let data = results.data else return
let decoder = JSONDecoder()
guard let stores = try? decoder.decode([Store].self, from: data) else return
completionHandler(stores, response.httpStatusCode)
else
completionHandler(nil, response.httpStatusCode)
从 RestManager 发出请求,我包含了 make 请求,因为我看到其他一些人使用共享数据发布任务,但我在尝试使用它时可能没有正确使用它。任何建议或帮助将不胜感激。谢谢!
func makeRequest(toURL url: URL,
withHttpMethod httpMethod: HttpMethod, useSessionCookie: Bool?,
completion: @escaping (_ result: Results) -> Void)
DispatchQueue.main.async [weak self] in
let targetURL = self?.addURLQueryParameters(toURL: url)
let httpBody = self?.getHttpBody()
// fetches cookies and puts in appropriate header and body attributes
guard let request = self?.prepareRequest(withURL: targetURL, httpBody: httpBody, httpMethod: httpMethod, useSessionCookie: useSessionCookie) else
completion(Results(withError: CustomError.failedToCreateRequest))
return
let sessionConfiguration = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfiguration)
let task = session.dataTask(with: request) (data, response, error) in
print(response)
completion(Results(withData: data,
response: Response(fromURLResponse: response),
error: error))
task.resume()
【问题讨论】:
【参考方案1】:您似乎是在尝试调用 Main 中的函数,而不是设置 stores 属性。一旦调用完成,调用request. getStoresList
已经在主线程中,您从那里进入后台线程,一旦 URLSession 完成,您需要返回主线程。您需要在主线程中进行 UI 修改,而不是在后台执行,因为错误清楚地说明了这一点。要解决此问题,您需要执行以下操作:
func getStores()
self.request.getStoresList() stores, status in
DispatchQueue.main.async
if stores != nil
self.request.stores = stores!
【讨论】:
哇,这个解决方案的旅程比我想要的要长得多。非常感谢!欣赏它 如果我们想设置一个值或更新 UI。需要添加 DispatchQueue.main.async。成功了,谢谢! 如果 dispatch 不是最后一个并且下面的代码依赖于 self,这是不安全的以上是关于如何从后台线程 Swift UI GET 请求发布更改的主要内容,如果未能解决你的问题,请参考以下文章
iOS / Swift(UI)始终运行的后台计算线程的高效实现-GCD案例?
从 GET 请求中解析 JSON 数组 Alamofire Swift 2