繁体   English   中英

如何在 Swift 中成功实现 async 和 await,什么是最好的使用方法

[英]How to successfully implement async and await in Swift, and whats the best method to use

基本上我正在尝试创建一个基本的登录页面,它将有一个 ContentView,它有一个在按下登录按钮时调用的方法。 将发生的情况是将用户名和密码发送到 NetworkManager class,它将评估 api,如果密码和用户名正确,它将返回 true,否则返回 false,这将更改 @Published 变量的真假。 在 ContentView 中观察到该特定变量以检查尝试登录是否成功。

我还有几个用于解码和编码的类。

现在我的问题是在我调用 NetworkManager 来检查 api 之后,我有一个条件来检查用户是否成功登录,但是因为网络调用返回的速度不够快,所以它总是返回 false,我该怎么做条件等待网络调用在继续之前返回。

在 java/C# 中,我只会使用 Async/Await,但对 swift 来说是新手,我尝试了几种不同的方法,但无法让它工作。 任何帮助,将不胜感激。 下面是我创建的三个 swift 文件、ContentView、NetworkManager class 以及用于构造发送和返回 json 数据的类。 由于显而易见的原因,我还更改了 api 的地址。 谢谢

内容视图

import SwiftUI

struct ContentView: View {
    
    @ObservedObject var networkManager = NetworkManager()
    let dispatchGroup = DispatchGroup()
    let dispatchQueue = DispatchQueue(label: "My Queue")
    
    @State private var usernameInput = ""
    @State private var passwordInput = ""
    @State private var returnType = ""
    //private var returnType = ""
    
    var body: some View {
        VStack{
            Text(networkManager.usernamesAndPass)
            TextField("Enter Username", text: $usernameInput)
            TextField("Pasword", text: $passwordInput)
            Button(action: {
                self.AttempLogin()
                })
                {
                    Text("Login")
                }
        }
        
    }
    
    func AttempLogin(){
        dispatchQueue.async(group: dispatchGroup) {
            self.networkManager.loginFunction(username: self.usernameInput, password: self.passwordInput)
        }
        dispatchQueue.async(group: dispatchGroup) {
            if(self.networkManager.loggedIn){
                print("You're now logged on")
            }
                else{
                    print("You aren't logged in")
                }
            }
        dispatchGroup.wait()
        print("Final")
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

网络管理器

import Foundation

class NetworkManager: ObservableObject {
    
    @Published var loggedIn = Bool()
    
    
    func loginFunction(username: String, password: String) {
        
        let url = URL(string: "https://example.com.au/TestPHP/users/login")
        
        let loginDetails = People(user_email: username, user_password: password)
         
        //CHeck to see if the guard encoding works
        let jsonData = try? JSONEncoder().encode(loginDetails)
        
        
        var request = URLRequest(url: url!)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")//the JSON request
        request.setValue("application/json", forHTTPHeaderField: "Accept") // the response expected to be in JSON format
        request.httpBody = jsonData
        
        let task = URLSession.shared.dataTask(with: request) { data, response, error in
          if let error = error {
              print("Error took place \(error)")
              return
          }
            
          guard let data = data else {return}
            do {
                let getResponse = try JSONDecoder().decode(Response.self, from: data)
                DispatchQueue.main.async {
                    self.loggedIn = getResponse.status
                }
                
            } catch let error {
                print("Error: Trying to convert JSON data to string")
                print(error)
                return
            }
        }
        task.resume()
    }
}

用户类

class Response: Codable {
    var status: Bool
    var message: String
}

class People: Codable {
    var user_emailaddress: String = String()
    var user_password: String = String()
    var status: String = String()
    var logedIn: Bool = Bool()
    var messaage: String = String()
    
    init(user_email: String, user_password: String){
        self.user_emailaddress = user_email
        self.user_password = user_password
    }
}

感谢任何人可以提供的任何帮助,任何真正擅长解释这一点的 tuts 都会很棒,正如我之前所说,我是 Swift 的新手,所以尽可能多的信息会很棒。 我的背景一般是 C# 和 Java,但尝试新事物总是好的。

您需要在登录 function 中添加回调以在异步操作完成时收到通知,例如

func loginFunction(username: String, password: String, onEnded: @escaping () -> () = {}) {
    var result = false

    // ... other code
    
    result = getResponse.status
    
    // ... other code

    // make sure you have this call once and definitely performed at the end, 
    // because your current implementation has many returns 
    // which prevent reporting any result
    DispatchQueue.main.async {
        self.loggedIn = result
        self.onEnded()                        // << callback
    }

} 所以代替电话

func AttempLogin(){
    self.networkManager.loginFunction(username: self.usernameInput, password: self.passwordInput) {
        // will be received at the login processed
        if self.networkManager.loggedIn {
            print("You're now logged on")
        }
        else{
            print("You aren't logged in")
        }
    }
}

注意:实际上您不需要组或显式队列来调用,因为 URLSession 已经异步执行数据任务。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM