从 JSON API SwiftUI 中的响应获取值 Xcode

Get value from JSON API response in SwiftUI Xcode

我需要 post 一个 https 请求来登录视图 (SwiftUI),我的代码遵循 getres.swift: 所以我需要从响应中获取价值并将其放在文本中

      import Foundation
        import Combine

        struct result: Decodable {
           let res, ordercount, rate: String
        }

        class getres: ObservableObject {

          let objectWillChange = PassthroughSubject<getres, Never>()
        @Published var authenticated = ""
          @Published var todos = [result]() {
              didSet {
                   objectWillChange.send(self)
              }
           }

            func auth(username: String, password: String) {
            guard let url = URL(string: "http://company.com/auth.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 fineldata=try! JSONDecoder().decode(result.self, from: data)


        DispatchQueue.main.async {
            self.todos = [fineldata]
            self.authenticated=fineldata.res


        }


 print(fineldata)









    }.resume()
          }

        }

并在登录页面中尝试显示其他视图

在这段代码中,我将从函数中获取值作为 json 响应 我将获取订单数和费率 我将其放在另一个视图中

 import SwiftUI

    struct ContentView: View {

    @State private var username: String = ""
    @State private var password: String = ""

    @ObservedObject   var manager = getres()


    var body: some View {

        VStack(alignment: .leading) {

            if manager.authenticated == "2"{
                                        userdetails()
                                    }else{


            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.auth(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()
        }
       }

在 userdetails 中,所以我需要从响应中获取值

struct userdetails: View {

  @State var controller = getres()
    var body : some View{
        ScrollView(Axis.Set.vertical, showsIndicators: true) {

            VStack(spacing: 20){
            Image("wlogo").renderingMode(.original);              HStack(spacing: 15){

                  Spacer()
                  VStack(alignment: .center, spacing: 10) {

                    Text(???).foregroundColor(Color.white).bold()
                        .font(.largeTitle)

                    Text("")
                    .foregroundColor(Color.white)
                        .font(.headline)                  }

                  Spacer()
              }}}}

如何从响应中获取订单数并输入 文本(???) 在查看用户详细信息中 例如 controller.todos.ordercount 我收到这个错误 “[result]”类型的值没有成员 'ordercount' 当我尝试 文字(controller.todos.ordercount) json 回应

{"res":"2","ordercount":"20","rate":"5"}

更新的答案

1.) 如果您只复制一部分代码会很有帮助 - 这对我们所有人来说都更容易复制 2.) 在手动复制或更改代码中的某些内容之前,您应该自己尝试您的代码。发现这样的错误很烦人:

如果manager.authenticated == "2"{ 用户详细信息() } 否则{

        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.auth(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()}

}

你在哪里添加 .padding() 到 if 语句....

3.) 你应该以人们可以理解 class if 的方式命名 class 名称,并以大写字母开头,就像 Apple 对所有 class 名称所做的那样

4.) 你还应该开始查看大写的名称(就像 Apple 一样) 5.) 因为我必须访问你的页面而你没有提供示例数据 and/or 密码我不知道那里有什么数据...

到目前为止,这是我的解决方案代码:

我添加了一些假数据,因为我无法访问你的数据....所以你可以看到一些细节。

struct ToDo: Decodable, Identifiable {

    var id = UUID().uuidString

    let res, ordercount, rate: String
}

class ToDoGetter: ObservableObject {

    let objectWillChange = PassthroughSubject<ToDoGetter, Never>()
    @Published var authenticated = ""
    @Published var todos = [ToDo]() {
        didSet {
            objectWillChange.send(self)
        }
    }

    let someFakingTodos = [
        ToDo(res: "a", ordercount: "5", rate: "75%"),
        ToDo(res: "b", ordercount: "52", rate: "5%"),
        ToDo(res: "c", ordercount: "566", rate: "7%"),
        ToDo(res: "d", ordercount: "53", rate: "33%"),
        ToDo(res: "e", ordercount: "15", rate: "44%"),
        ToDo(res: "f", ordercount: "345", rate: "10%")

    ]

    func auth(username: String, password: String) {
        guard let url = URL(string: "http://company.com/auth.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 fineldata=try! JSONDecoder().decode(ToDo.self, from: data)

            DispatchQueue.main.async {
                self.todos = [fineldata]
                self.authenticated=fineldata.res
            }
            print(fineldata)
        }.resume()
    }
}

struct ContentView: View {

    @EnvironmentObject var todoGetter : ToDoGetter

    @State private var username: String = ""
    @State private var password: String = ""


    @State var navigateToDetail : Bool = false

    var body: some View {
        NavigationView {
            VStack(alignment: .leading) {

                if todoGetter.authenticated == "2"{
                    Userdetails().environmentObject(todoGetter)
                } else{

                    Text("Username")
                    TextField("placeholder", text: $username)
                        .textFieldStyle(RoundedBorderTextFieldStyle())
                        .border(Color.green)
                        .autocapitalization(.none)

                    Text("Password")
                    SecureField("placeholder", text: $password)
                        .textFieldStyle(RoundedBorderTextFieldStyle())
                        .border(Color.green)

                    NavigationLink(destination: Userdetails(), isActive: self.$navigateToDetail) {
                        EmptyView() }
                        .hidden()
                        .padding()

                    Button(action: {

                        self.todoGetter.auth(username: self.username, password: self.password)
                        self.navigateToDetail.toggle()
                    }) {
                        HStack{
                            Spacer()
                            Text("Login")
                            Spacer()
                        }
                        .accentColor(Color.white)
                        .padding(.vertical, 10)
                        .background(Color.red)
                        .cornerRadius(5)
                        .padding(.horizontal, 40)
                    }
                }
            }
        }
    }
}

struct Userdetails: View {

    @EnvironmentObject var todoGetter : ToDoGetter

    var body : some View{

        VStack(spacing: 20) {
            Image("wlogo").renderingMode(.original);              HStack(spacing: 15){

                Spacer()

                List(todoGetter.someFakingTodos) { todo in

                    VStack(alignment: .center, spacing: 10) {
                        HStack {
                            Text(todo.res).foregroundColor(Color.white).bold()
                                .font(.largeTitle)

                            Text(todo.ordercount)
                                .foregroundColor(Color.white)
                                .font(.headline)
                            Text(todo.rate)
                                .foregroundColor(Color.white)
                                .font(.headline)
                        }
                    }.background(Color.black)

                    Spacer()
                }
            }
        }
    }
}

旧答案

你给 getres 打了 2 次电话。您只需调用它一次,然后将值赋给 detailview。

每个应用只能创建一次模型。