通过 SwiftUI 中异步命令中的条件语句更改视图 IOS15

Changing views via conditional statements inside of async commands in SwiftUI IOS15

我试图让用户进入 ContentView 并登录,现在这将让他们登录或 return 到 ContentView(稍后将创建错误和登录失败的东西)。目前我可以登录并从我的 API 中提取所需的数据,然后 运行 如果成功则条件为真,否则为假。条件内部是打印语句,如果为真则为成功,如果为假则为不成功。这一切 运行 都很好,但是当我放入一个语句来更改视图时,它不会更改视图。我确定它与 async/await 有关,但我对 SwiftUI 还很陌生。我已经包含了 ContentView 代码以供参考。这不是一个超级复杂的过程,但我似乎找不到太多关于以这种方式改变视图的信息。这可能是错误的方法,所以任何建议都会很棒。

import SwiftUI

struct ContentView: View {
    @State var username : String = ""
    @State var password : String = ""
    @State var loggedIn : Bool = false
    @State var network = NetworkCall()
    var body: some View {
        ZStack {
            Color(red: 0.4627, green: 0.8392, blue: 1.0).ignoresSafeArea()
            VStack {
                Text("Login")
                    .padding()
                TextField("Username", text: $username)
                    .padding()
                SecureField("Password", text: $password)
                    .padding()
                
                Button(action: {
                    Task {
                        do{
                            try await loggedIn = network.LoginFunction(userName: username, passWord: password)
                            if(loggedIn){
                                print("Login Successful")
                                Dashboard()
                            }
                            else {
                                print("Login Unsuccessful")
                                ContentView()
                            }
                        }catch{
                            print("error", error)
                        }                        
                    }
                }) {
                    Text("Sign in")
                        .padding()
                        .frame(minWidth: 100, maxWidth: 300, minHeight: 44)
                        .foregroundColor(Color.white)
                        .cornerRadius(30)
                        .background(Color.blue)
                        .cornerRadius(20)
                }
            }
        }
    }
}

网络呼叫者

import Foundation
class NetworkCall {
    func LoginFunction(userName: String, passWord: String) async throws -> Bool {
        
        let parameters = "{\r\n    \"uEmail\" : \"" + userName + " \",\r\n    \"uPassword\" : \"" + passWord + "\" \r\n}"
        let postData = parameters.data(using: .utf8)
        
        var request = URLRequest(url: URL(string: "https://..........................")!,timeoutInterval: Double.infinity)
        
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        request.httpMethod = "POST"
        request.httpBody = postData

        let (data, response) = try await URLSession.shared.data(for: request)
        guard (response as? HTTPURLResponse)?.statusCode == 200 else { fatalError("Error while fetching data") }
        let decodedUser = try JSONDecoder().decode(UserClass.self, from: data)
        print(decodedUser.userinfo.user_guid)
        
        if(decodedUser.status){
            return true
        }
        else{
            return false
        }
    }

}


SwiftUI 呈现您的用户界面以响应状态变化。因此,与其尝试在 Task 中呈现 DashboardContentView,不如将某种形式的状态设置得更高,以确定向用户显示哪个视图。

例如,如果您有一个 @State 变量记录您的登录状态,您的代码将开始看起来像

struct ContentView: View {
  @State var loggedIn = false

  var body: some View {
    if loggedIn {
      Dashboard()
    } else {
      // login form
      Button {
        Task {
          let logInStatus = try await network.LoginFunction(userName: username, passWord: password)
          self.loggedIn = logInStatus
        }
      }
    }
  }
}

当您的 async 任务更改了 ContentView 的状态时,SwiftUI 的渲染子系统会发现 loggedIn 已更改,并重新渲染 body 以便登录表单被替换为调用 Dashboard().

您可能要考虑的另一种方法是创建两个视图:

  • 登录查看
  • 仪表板视图

两者都放置在 ContentView 中,并且您在 ContentView 中处于登录状态。并且您显示哪个视图取决于此登录状态。

您可以将此 loggenIn 状态传递给 LoginView,以便它可以根据 API 的登录结果修改它。