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

时间:2020-03-28 11:56:43

标签: json api swiftui xcode11.2

我需要发布一个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响应的函数中获取值,将获得ordercount和费率,并将其放入其他视图中

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

并且在用户中有详细说明,所以我需要从响应中获取值

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 我得到这个错误 类型“ [结果]”的值没有成员“订单数” 当我尝试 文字(controller.todos.ordercount) json响应

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

1 个答案:

答案 0 :(得分:0)

更新后的答案

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

如果manager.authenticated ==“ 2” { userdetails() }其他{

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

}

要在.if语句中添加.padding()的地方...。

3。)您应该以这种方式命名班级名称,这样人们就可以理解该班级的用途,并以大写字母开头,例如Apple会使用所有班级名称

4。)您还应该开始将名称大写(如Apple一样) 5.)由于我必须访问您的页面,而您没有提供示例数据和/或密码,所以我不知道会有什么数据...

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

我添加了一些伪造数据,因为我无法访问您的数据..所以您可以看到一些详细信息。

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。

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