为啥 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 源码解析 ( 事件发送 | 发布线程为 子线程 切换到 主线程 执行订阅方法的过程分析 )

为啥使用超过 2 个线程会消耗更多时间?

EventBusEventBus 源码解析 ( 事件发送 | 线程池中执行订阅方法 )

Gitbook章节参考书目不按字母顺序排列