Http-запрос SwiftUI - PullRequest
       73

Http-запрос SwiftUI

0 голосов
/ 10 ноября 2019

Мне нужно опубликовать http-запрос для просмотра входа в систему (SwiftUI), мой код следующий у меня в 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, «self.manager.authenticated» в ContentView не обновляется из класса HttpAuth.

Эта часть кода неработа:

if self.manager.authenticated {
        Text("Correct!").font(.headline)
    }

«Аутентифицированный» все еще на ложном.

Как я могу это исправить, спасибо.

Ответы [ 2 ]

1 голос
/ 10 ноября 2019

вы можете попробовать это:

вместо

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

, тогда она должна работать.

0 голосов
/ 11 ноября 2019

Хотя принятый ответ соответствует цели, я не думаю, что это лучший способ сделать это, потому что он реализует @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()
        }
    }
}
...