通过 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
中呈现 Dashboard
或 ContentView
,不如将某种形式的状态设置得更高,以确定向用户显示哪个视图。
例如,如果您有一个 @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 的登录结果修改它。
我试图让用户进入 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
中呈现 Dashboard
或 ContentView
,不如将某种形式的状态设置得更高,以确定向用户显示哪个视图。
例如,如果您有一个 @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 的登录结果修改它。