为啥 Swiftui 中主线程不按顺序排列
Posted
技术标签:
【中文标题】为啥 Swiftui 中主线程不按顺序排列【英文标题】:Why the main thread is not in sequence in Swiftui为什么 Swiftui 中主线程不按顺序排列 【发布时间】:2020-09-20 01:23:30 【问题描述】:我在 SwiftUI 中有以下功能。 JSON 正在解析正确的数据,但顺序是:P1、P2、P5、P6、P3 和 P4。我需要 P1、P2、P3、P4、P5 和 P6。有人可以帮我吗?我不明白为什么不遵循逻辑线程。
struct ContentView: View
var body: some View
Button ("Action", action: self.checkLogin(username:"test", password:"123456") )
func checkLogin (username: String, password: String)
var body: [String:String] = [:]
guard let url = URL(string: "http://test/apple/login.php") else return
body = ["user": username, "password": password]
let finalBody = try! JSONEncoder().encode (body)
print("final",body)
var request = URLRequest(url: url)
print("p1")
request.httpMethod = "POST"
request.httpBody = finalBody
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
print("p2")
let task = URLSession.shared.dataTask(with: request) (data,response,error) in
print("p3")
if let error = error print ("Error: \(error)")
return
guard let data = data else return
do
print("p4")
let finalData = try! JSONDecoder().decode(ServerMessage.self, from: data)
print (finalData)
print ("p5")
task.resume()
print ("p6")
return
struct ServerMessage: Decodable
let result: String
let nuser: String
【问题讨论】:
在某处了解异步流(编程)概念,例如。 medium.com/ios-os-x-development/…. 【参考方案1】:您创建的 URLSession 有一个名为 dataTask 的函数,它在后台线程上执行:
let task = URLSession.shared.dataTask(with: request) (data,response,error) in
print("p3")
if let error = error print ("Error: \(error)")
return
guard let data = data else return
do
print("p4")
let finalData = try! JSONDecoder().decode(ServerMessage.self, from: data)
print (finalData)
在调用task.resume()之前它不会被执行,这就是原因
print("p5")
首先被调用,并将在您的控制台上注册日志。
当 task.resume() 被调用时,它会在另一个线程中执行,从而使执行与主线程异步。这意味着主线程将立即执行
print ("p6")
后台线程大约在同一时间执行“任务”:执行请求并等待响应。一旦有响应,就会执行:
print("p3")
如果请求没有错误,
print("p4")
将执行,如果响应的数据有错误,您将不会在控制台上看到“p4”打印出来,因为您对此有所防范。
为保证您获得所需的订单结果,您必须将打印调用放在该 API 的完成处理程序中
let task = URLSession.shared.dataTask(with: request) (data,response,error) in
print("p3")
if let error = error
print ("Error: \(error)")
return
guard let data = data else return
do
let finalData = try! JSONDecoder().decode(ServerMessage.self, from: data)
print (finalData)
// Here is where you put non-UI code after you get a successful
// response and will guarantee that you get your data first
print("p4")
// Also keep in mind that since this is a background thread,
// you need to call the main thread in order to make your UI changes
DispatchQueue.main.async
// All your UI changes here, so they will run on the main thread
print("p5")
print("p6")
catch
print("Error parsing data")
task.resume()
return
Apple 已弃用您之前可以使用 NSURLConnection 执行的同步请求 API,请参见此处:https://developer.apple.com/documentation/foundation/nsurlconnection/1411393-sendsynchronousrequest?language=objc
这是因为用户不会喜欢无响应的应用。让网络调用阻塞主线程就可以做到这一点。
您可以在此处阅读更多关于闭包的信息https://docs.swift.org/swift-book/LanguageGuide/Closures.html
【讨论】:
@EduardoMartinez 您不需要在主线程上运行任务,也不需要 P1-P6 的顺序。您需要了解异步数据处理的工作原理。 经过一番挖掘,我发现苹果不推荐使用同步请求是有原因的,见这里:developer.apple.com/documentation/foundation/nsurlconnection/… 我已更新我的答案以反映这一点。希望这会有所帮助,祝你好运! 非常感谢乔安娜。我是 swiftui 的新手。对于日志屏幕,我需要一个函数来验证用户是否已注册。我该怎么做?我需要服务器回答才能给予访问权。请问有什么线索吗? 嘿@EduardoMartinez,我已经修改了我的答案,以说明最好将代码放在哪里以达到您想要的顺序。希望这会有所帮助!以上是关于为啥 Swiftui 中主线程不按顺序排列的主要内容,如果未能解决你的问题,请参考以下文章
多线程 CoreData 应用程序中主上下文和私有上下文的推荐合并策略
EventBusEventBus 源码解析 ( 事件发送 | 发布线程为 子线程 切换到 主线程 执行订阅方法的过程分析 )