正在解析 JSON 响应并在 swiftui 屏幕上显示

parsing JSON response and displaying on swiftui screen

各位。在我的项目中,出于某种原因我无法显示 json 数据。一般来说,我不知道如何提取和使用 json 对象中的数据 ?!

这些是我的尝试
在此先感谢您的回答和关注!!

[这是我需要显示的api][]

http://dummy.restapiexample.com/#:~:text=http%3A//dummy.restapiexample.com/api/v1/employees

{
"status": "success",
"data": [
    {
     "id": "1",
     "employee_name": "Tiger Nixon",
     "employee_salary": "320800",
     "employee_age": "61",
     "profile_image": ""
    },
    {
      "id": 2,
      "employee_name": "Garrett Winters",
      "employee_salary": 170750,
      "employee_age": 63,
      "profile_image": ""
        },
        {
      "id": 3,
      "employee_name": "Ashton Cox",
      "employee_salary": 86000,
      "employee_age": 66,
      "profile_image": ""
        },
        {
       "id": 4,
       "employee_name": "Cedric Kelly",
       "employee_salary": 433060,
       "employee_age": 22,
       "profile_image": ""
        },
      ...
    ]
}

(1) 这是我的模型:Employee

import Foundation

struct Employee: Decodable {
    var success: String?
    var data:  [Details]?
    var message: String?


    struct Details: Decodable {
    var id: Int?
    var employee_name: String?
    var employee_salary: Int?
    var employee_age: Int?
    var profile_image: String?
    }
}

(2 ) 使用 AF(alamofire)

import Foundation
import Alamofire

private let IS_TESTER = true
private let DEP_SER = "https://dummy.restapiexample.com/"
private let DEV_SER = "https://dummy.restapiexample.com/"

let headers: HTTPHeaders = [
    "Accept": "application/json"
]

//CustomClass
class AF_Talking {
    
    //MARK: AF_Talking Requests 
    class func get(url: String, params: Parameters, handler: @escaping (AFDataResponse<Any>) -> Void) {
        AF.request(server(url: url), method: .get, parameters: params, headers: headers).validate().responseJSON(completionHandler: handler)
    }
    
    
    //MARK: AF_Talking Methods
    class func server(url: String) -> URL {
        if(IS_TESTER) {
            return URL(string: DEV_SER + url)!
        } else {
            return URL(string: DEP_SER + url)!
        }
    }
    
    //MARK: AF_Talking APIs
    static let API_EMPLOYEES_LIST = "api/v1/employees"  // list
    
    //MARK: AF_Talking APIs

    class func paramsEmpty() -> Parameters {
        let parameters: Parameters = [
            :]  // <-  shouldn't there be some change here?
        return parameters
    }
}

(3) 抓取

import Foundation

class EmployeeView: ObservableObject {
    
    @Published var employees = Employee().data // of course, is an error
    @Published var isLoading = false
    
    func apiEmployeesList() {
        isLoading = true
        AF_Talking.get(url: AF_Talking.API_EMPLOYEES_LIST, params: AF_Talking.paramsEmpty(), handler: { response in
            self.isLoading = false
            switch response.result {
            case .success:
                print(response.result)
                let employees = try! JSONDecoder().decode(Employee().data.self, from: response.data!)
                self.employees = employees
            case let .failure(error):
                print(error)
            }
        })
    }
}

(4) 主视图

import SwiftUI
import Alamofire

struct MainView: View {
    
    @ObservedObject var viewModel = EmployeeView()
    
    var body: some View {
        NavigationView {
            ZStack {
                List(viewModel.employees.data!, id: \.id) { employee in // 
                    VStack {
                        Text(employee.employee_name!.uppercased()).fontWeight(.bold)
                        Text(employee.employee_salary!).padding(.top)
//                        Text(employee.employee_age!).padding(.top)
                    }
                }
                if viewModel.isLoading {
                    ProgressView()
                }
            }
            .navigationBarItems(trailing: NavigationLink(destination: DetailView(), label: {    Text("Next Page")   }))
        }.onAppear {
            viewModel.apiEmployeesList()
        }
    }
}

struct MainView_Previews: PreviewProvider {
    static var previews: some View {
        MainView()
    }
}

问题:取嵌套的jsonobj。并在模拟器上显示

首先命名根结构 Response 和员工 Employee.

其次如果 API 发送所有字段声明属性 non-optional。

第三,如果属性不会被修改,则将它们声明为常量 (let)。

进一步添加CodingKeys并采用Identifiable,因为id已经存在


根结构中存在错误。没有键 success,但有一个键 status,值为 success

struct Response: Decodable {
    let status: String
    let data:  [Employee]
    let message: String


    struct Employee: Decodable, Identifiable {
        let id: Int
        let name: String
        let salary: Int
        let age: Int
        let profileImage: String
        
        private enum CodingKeys: String, CodingKey {
            case id
            case name = "employee_name"
            case salary = "employee_salary"
            case age = "employee_age"
            case profileImage = "profile_image"
        }
    }
}

自动对焦部分太复杂了。大多数代码是不需要的。 Talking class 实际上根本不需要。并且命名再次令人困惑。将其命名为 EmployeeModel

class EmployeeModel: ObservableObject {

    @Published var employees = [Response.Employee]()
    @Published var isLoading = false

    func apiEmployeesList() {
        let url = URL(string: "http://dummy.restapiexample.com/api/v1/employees")!
        isLoading = true
        AF.request(url).validate().responseDecodable(of: Response.self, decoder: JSONDecoder()) { response in
            self.isLoading = false
            switch response.result {
                case .success(let result):
                    print(result)
                    self.employees = result.data
                case .failure(let error):
                    print(error)
            }
        }
    }
}

这个观点几乎是正确的。

import SwiftUI

struct MainView: View {
    
    @StateObject var viewModel = EmployeeModel()
    
    var body: some View {
        NavigationView {
            ZStack {
                List(viewModel.employees) { employee in                        
                    VStack(alignment: .leading, spacing: 10) {
                        Text(employee.name.uppercased()).bold()
                        Text(String(employee.salary))
                        Text(String(employee.age))
                    }
                }
                if viewModel.isLoading {
                    ProgressView()
                }
            }
            .navigationBarItems(trailing: NavigationLink(destination: DetailView(), label: {    Text("Next Page")   }))
        }.onAppear {
            viewModel.apiEmployeesList()
        }
    }
}

struct MainView_Previews: PreviewProvider {
    static var previews: some View {
        MainView()
    }
}