Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI http request

I need to post a http request to login view (SwiftUI), my code follow I have in 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()

  }

}

And in 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()
    }
   }

It works, i receive the answer from server but it doesn't update the ContentView, the 'self.manager.authenticated' in ContentView doesn't refresh from HttpAuth class.

This part of code doesn't work:

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

The 'authenticated' still on false.

How can i fix it, thank you.

like image 981
Paolo Gdf Avatar asked Nov 10 '19 11:11

Paolo Gdf


1 Answers

Although the accepted answer meets the objective I don't think it's the best way to do it because it implements @EnvironmentObject and it should be used for global application issues and not for the specific request of a view.

You can implement a "ViewModel" that is specific for the view, to do the work of the request and make the update of the variable.

Documentation: https://developer.apple.com/documentation/combine/observableobject

The implementation for your code would be like this, based on the changes suggested by @Chris:

This works in Xcode Version 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()
        }
    }
}
like image 90
Esteban Avatar answered Sep 27 '22 19:09

Esteban