web-dev-qa-db-ja.com

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)
    }

「認証済み」はまだfalseです。

どうすれば修正できますか、ありがとうございます。

2
Paolo Gdf

あなたはこれを試すことができます:

の代わりに

let objectWillChange = PassthroughSubject<HttpAuth, Never>()

  var authenticated = false {
      didSet {
           objectWillChange.send(self)
      }
   }

使用する

@published var authenticated = false

代わりに

@State var manager = HttpAuth()

使用する

@EnvironmentObject private var manager: HttpAuth

そしてもちろん、ContentViewを呼び出すときにこれを行います。

ContentView().environmentObject(manager)

グローバル変数のようにクラスの外のどこか

var manager = HttpAuth()

その後、動作するはずです。

1
Chris

受け入れられた回答は目的を満たしていますが、@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()
    }
}

ContentView.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()
        }
    }
}
1
Esteban