swiftui - SwiftUI http 请求
问题描述
我需要向登录视图 (SwiftUI) 发布一个 http 请求,我的代码遵循我在 HttpAuth.swift 中的代码:
import Foundation
import Combine
struct ServerMessage: Decodable {
let res, message: String
}
class HttpAuth: ObservableObject {
let objectWillChange = PassthroughSubject<HttpAuth, Never>()
var authenticated = false {
didSet {
objectWillChange.send(self)
}
}
func postAuth(username: String, password: String) {
guard let url = URL(string: "http://mysite/loginswift.php") else { return }
let body: [String: String] = ["username": username, "password": password]
let finalBody = try! JSONSerialization.data(withJSONObject: body)
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = finalBody
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
URLSession.shared.dataTask(with: request) { (data, response, error) in
guard let data = data else { return }
let resData = try! JSONDecoder().decode(ServerMessage.self, from: data)
print(resData.res)
if resData.res == "correct" {
DispatchQueue.main.async {
self.authenticated = true
}
}
}.resume()
}
}
在 ContentView.swift 中:
import SwiftUI
struct ContentView: View {
@State private var username: String = ""
@State private var password: String = ""
@State var manager = HttpAuth()
var body: some View {
VStack(alignment: .leading) {
if self.manager.authenticated {
Text("Correct!").font(.headline)
}
Text("Username")
TextField("placeholder", text: $username)
.textFieldStyle(RoundedBorderTextFieldStyle())
.border(Color.green)
.autocapitalization(.none)
Text("Password")
SecureField("placeholder", text: $password)
.textFieldStyle(RoundedBorderTextFieldStyle())
.border(Color.green)
Button(action: {
self.manager.postAuth(username: self.username, password: self.password)
}) {
HStack{
Spacer()
Text("Login")
Spacer()
}
.accentColor(Color.white)
.padding(.vertical, 10)
.background(Color.red)
.cornerRadius(5)
.padding(.horizontal, 40)
}
}.padding()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
它有效,我从服务器收到答案,但它没有更新 ContentView,ContentView 中的“self.manager.authenticated”不会从 HttpAuth 类刷新。
这部分代码不起作用:
if self.manager.authenticated {
Text("Correct!").font(.headline)
}
“认证”仍然是假的。
我该如何解决它,谢谢。
解决方案
虽然接受的答案符合目标,但我认为这不是最好的方法,因为它实现@EnvironmentObject
并且它应该用于全局应用程序问题,而不是用于视图的特定请求。
您可以实现特定于视图的“ViewModel”,以完成请求的工作并更新变量。
文档:https ://developer.apple.com/documentation/combine/observableobject
根据@Chris 建议的更改,您的代码实现将是这样的:
这适用于 Xcode 版本 11.2 (11B52)
HttpAuth.swif:
import Foundation
import SwiftUI
import Combine
class HttpAuth: ObservableObject {
@Published var authenticated = false
func postAuth(username: String, password: String) {
guard let url = URL(string: "http://mysite/loginswift.php") else { return }
let body: [String: String] = ["username": username, "password": password]
let finalBody = try! JSONSerialization.data(withJSONObject: body)
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = finalBody
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
URLSession.shared.dataTask(with: request) { (data, response, error) in
guard let data = data else { return }
let resData = try! JSONDecoder().decode(ServerMessage.self, from: data)
print(resData.res)
if resData.res == "correct" {
DispatchQueue.main.async {
self.authenticated = true
}
}
}.resume()
}
}
内容视图.swift
import SwiftUI
struct ContentView: View {
@State private var username: String = ""
@State private var password: String = ""
@ObservedObject var manager = HttpAuth()
var body: some View {
VStack(alignment: .leading) {
if self.manager.authenticated {
Text("Correct!").font(.headline)
}
Spacer()
Text("Username")
TextField("placeholder", text: $username)
.textFieldStyle(RoundedBorderTextFieldStyle())
.border(Color.green)
.autocapitalization(.none)
Text("Password")
SecureField("placeholder", text: $password)
.textFieldStyle(RoundedBorderTextFieldStyle())
.border(Color.green)
Button(action: {
self.manager.postAuth(username: self.username, password: self.password)
}) {
HStack{
Spacer()
Text("Login")
Spacer()
}
.accentColor(Color.white)
.padding(.vertical, 10)
.background(Color.red)
.cornerRadius(5)
.padding(.horizontal, 40)
}
Spacer()
}.padding()
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
}
推荐阅读
- javascript - 如何从这种字符串中获取关键字
- flutter - Flutter和OneSignal,如何在与初始化位置不同的页面中捕获通知
- javascript - 有没有办法在附加回调之前判断是否有错误?
- javascript - HttpTestingController 通过 HttpParams 测试正确的 x-www-form-urlencoded 字段
- verilog - 当我与iverilog中的1'bx进行比较时,为什么===不起作用?
- ios - 我想添加比两个更多的标签栏
- java - 如何为方法参数定义多个可接受的类类型?
- batch-file - 使用 CMDER,设置 PATH 时出现问题
- javascript - 如何使自定义光标显示在图像上?
- html - 如何在背景颜色穿过文本时为文本颜色设置动画