正在解析 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()
}
}
各位。在我的项目中,出于某种原因我无法显示 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()
}
}