SwiftUI LoginView 登录后不消失
SwiftUI LoginView not disappearing after login
我正在使用 AppStateView()
检查用户是否登录:
struct AppStateView: View {
@EnvironmentObject var appState: AppState
var body: some View {
if (self.appState.user != nil) {
return AnyView(ContentView().environmentObject(appState))
} else {
return AnyView(LoginView().environmentObject(appState))
}
}
}
里面LoginView()
:
struct LoginView: View {
@EnvironmentObject var appState: AppState
@State private var username: String = ""
@State private var password: String = ""
var body: some View {
NavigationView {
VStack {
TextField("Username", text: $username)
SecureField("Password", text: $password)
Button(action: {
self.appState.login(username: self.username, password: self.password) { user in
if user.accountId != 0 {
print("logged in")
} else {
print("not logged in")
}
}
}) {
Text("LOGIN")
}
NavigationLink(destination: RegisterView()) {
Text("Sign Up")
}
}
}
}
}
有一个调用appState.login函数的按钮:
struct User: Codable {
let uid: Int
let name: String
let accountname: String
let accountId: Int
let startBalance: Double
}
class AppState: ObservableObject {
@Published var user: User? = nil
let apiURL: String = "http://localhost/api.php?"
init() {
if let user = UserDefaults.standard.object(forKey: "user") as? Data {
if let loadedUser = try? JSONDecoder().decode(User.self, from: user) {
self.user = loadedUser
}
}
}
func login(username: String, password: String, completion: @escaping (User) -> ()) {
let urlstring = "\(apiURL)get_users&username=\(username)&password=\(password)"
guard let url = URL(string: urlstring) else { return }
URLSession.shared.dataTask(with: url) { (data, _, error) in
guard let data = data, error == nil else {
debugPrint("Fehler beim Laden von \(url)", String(describing: error))
return
}
let user = try! JSONDecoder().decode(User.self, from: data)
if let encoded = try? JSONEncoder().encode(user) {
UserDefaults.standard.set(encoded, forKey: "user")
}
DispatchQueue.main.async {
completion(user)
}
}.resume()
}
func logout() {
self.user = nil
UserDefaults.standard.removeObject(forKey: "user")
}
}
根据我对可观察对象的理解,我认为,在按下登录按钮后,用户会得到更新,因此 LoginView()
视图会在用户登录时重新加载。但它必须切换到 AppStateView()
。在 LoginView()
中添加第二个检查以显示 LoginView()
或 AppStateView()
感觉有点奇怪,因为我已经在 "parent view" [=13= 中这样做了].
下面是固定的部分代码
Button(action: {
self.appState.login(username: self.username, password: self.password) { user in
if user.accountId != 0 {
print("logged in")
self.appState.user = user // << here !!
} else {
print("not logged in")
}
}
}) {
Text("LOGIN")
}
我正在使用 AppStateView()
检查用户是否登录:
struct AppStateView: View {
@EnvironmentObject var appState: AppState
var body: some View {
if (self.appState.user != nil) {
return AnyView(ContentView().environmentObject(appState))
} else {
return AnyView(LoginView().environmentObject(appState))
}
}
}
里面LoginView()
:
struct LoginView: View {
@EnvironmentObject var appState: AppState
@State private var username: String = ""
@State private var password: String = ""
var body: some View {
NavigationView {
VStack {
TextField("Username", text: $username)
SecureField("Password", text: $password)
Button(action: {
self.appState.login(username: self.username, password: self.password) { user in
if user.accountId != 0 {
print("logged in")
} else {
print("not logged in")
}
}
}) {
Text("LOGIN")
}
NavigationLink(destination: RegisterView()) {
Text("Sign Up")
}
}
}
}
}
有一个调用appState.login函数的按钮:
struct User: Codable {
let uid: Int
let name: String
let accountname: String
let accountId: Int
let startBalance: Double
}
class AppState: ObservableObject {
@Published var user: User? = nil
let apiURL: String = "http://localhost/api.php?"
init() {
if let user = UserDefaults.standard.object(forKey: "user") as? Data {
if let loadedUser = try? JSONDecoder().decode(User.self, from: user) {
self.user = loadedUser
}
}
}
func login(username: String, password: String, completion: @escaping (User) -> ()) {
let urlstring = "\(apiURL)get_users&username=\(username)&password=\(password)"
guard let url = URL(string: urlstring) else { return }
URLSession.shared.dataTask(with: url) { (data, _, error) in
guard let data = data, error == nil else {
debugPrint("Fehler beim Laden von \(url)", String(describing: error))
return
}
let user = try! JSONDecoder().decode(User.self, from: data)
if let encoded = try? JSONEncoder().encode(user) {
UserDefaults.standard.set(encoded, forKey: "user")
}
DispatchQueue.main.async {
completion(user)
}
}.resume()
}
func logout() {
self.user = nil
UserDefaults.standard.removeObject(forKey: "user")
}
}
根据我对可观察对象的理解,我认为,在按下登录按钮后,用户会得到更新,因此 LoginView()
视图会在用户登录时重新加载。但它必须切换到 AppStateView()
。在 LoginView()
中添加第二个检查以显示 LoginView()
或 AppStateView()
感觉有点奇怪,因为我已经在 "parent view" [=13= 中这样做了].
下面是固定的部分代码
Button(action: {
self.appState.login(username: self.username, password: self.password) { user in
if user.accountId != 0 {
print("logged in")
self.appState.user = user // << here !!
} else {
print("not logged in")
}
}
}) {
Text("LOGIN")
}