[英]SwiftUI macOS JSON convert in class Codable
I get the following json from an api call but am having trouble making the proper structure in swift and then getting the data as an array.我从 api 调用中得到以下 json,但在 swift 中创建正确的结构然后将数据作为数组获取时遇到了问题。
JSON: JSON:
{
"status":"ok",
"users":[
{
"position":0,
"user":{
"pk":"",
"full_name":"",
"username":"",
"profile_pic_url":""
}
},...
]
}
Swift: Swift:
class Response: Codable {
var status: String
var users: [User]?
}
class User: Identifiable, Codable {
var uuid = UUID()
var pk: String
var full_name: String
var username: String
var profile_pic_url: String
enum CodingKeys: String, CodingKey {
case
pk = "user.pk",
full_name = "user.full_name",
username = "user.username",
profile_pic_url = "user.profile_pic_url"
}
}
class Fetch: ObservableObject {
@Published var results = [User]()
@Published var resultState = false
@Published var errorState = false
init(url: String) {
self.results = []
let url = URL(string: url)!
URLSession.shared.dataTask(with: url) { data, response, error in
do {
if let data = data {
let results = try JSONDecoder().decode(Response.self, from: data)
DispatchQueue.main.async {
self.results = results.users ?? []
self.resultState = true
}
print("Widget: Ok.")
} else {
self.results = []
self.resultState = true
print("Widget: No data.")
}
} catch {
self.errorState = true
self.resultState = true
print("Widget: Error", error)
}
}.resume()
}
}
Code:代码:
@ObservedObject var fetch = Fetch(url: "")
List(fetch.results) { user in
UserItem(user: user)
}
The problem is that inside array users, it contains an object, this object contains two elements a position attribute and then the user object.问题是在数组用户内部,它包含一个 object,这个 object 包含两个元素 position 属性,然后是用户 object。
What I think I'm doing wrong is taking the user object.我认为我做错的是占用了用户 object。
Can anyone help me out?谁能帮我吗?
Edit:编辑:
struct Response: Codable {
let status: String
let users: [UserType]?
}
struct UserType: Codable {
let position: Int
let user: User
}
struct User: Codable {
let pk: String
let full_name: String
let username: String
let profile_pic_url: String
enum CodingKeys: String, CodingKey {
case pk, full_name, username, profile_pic_url
}
}
class Fetch: ObservableObject {
@Published var results = [User]()
@Published var resultState = false
@Published var errorState = false
init(url: String) {
self.results = []
let url = URL(string: url)!
URLSession.shared.dataTask(with: url) { data, response, error in
do {
if let data = data {
let results = try JSONDecoder().decode(Response.self, from: data)
let users = results.users?.map { $0.user }
DispatchQueue.main.async {
self.results = users ?? []
self.resultState = true
}
print("Widget: Ok.")
} else {
self.results = []
self.resultState = true
print("Widget: No data.")
}
} catch {
self.errorState = true
self.resultState = true
print("Widget: Error", error)
}
}.resume()
}
}
List(fetch.results) { user in
UserItem(user: user)
}
You need an extra struct that holds the User type您需要一个额外的结构来保存 User 类型
struct UserType: Codable {
let position: Int
let user: User
}
Meaning the top type becomes意味着顶级类型变为
struct Response: Codable {
let status: String
let users: [UserType]?
}
You also need to change the CodingKeys
enum since it should just contain the property names which mean the enum can be written as您还需要更改
CodingKeys
枚举,因为它应该只包含属性名称,这意味着枚举可以写为
enum CodingKeys: String, CodingKey {
case pk, full_name, username, profile_pic_url
}
For completeness here is the full User
type为了完整起见,这里是完整的
User
类型
struct User: Identifiable, Codable {
var uuid = UUID()
var pk: String
var full_name: String
var username: String
var profile_pic_url: String
enum CodingKeys: String, CodingKey {
case pk, full_name, username, profile_pic_url
}
}
and when decoding then you can extract the users array with the map
function在解码时,您可以使用
map
function 提取用户数组
do {
let results = try JSONDecoder().decode(Response.self, from: data)
let users = results.users?.map { $0.user }
....
Note that I changed from class to struct because struct is better suited for this but class works as well.请注意,我从 class 更改为 struct,因为 struct 更适合此用途,但 class 也适用。 I also wonder why the
users
property is optional, I didn't change that but can the array really be nil?我也想知道为什么
users
属性是可选的,我没有改变它但是数组真的可以为零吗?
You can try this.你可以试试这个。
struct Response: Codable {
let status: String
let users: [UserWPosition]
var userNoPositions: [UserInfo] { // computed value with only array of userinfo
users.compactMap { $0.user }
}
}
// MARK: - User with position object
struct UserWPosition: Codable {
let position: Int // commenting this will also do no effect
let user: UserInfo
}
// MARK: - UserInfo
struct UserInfo: Codable {
let pk, fullName, username, profilePicURL: String
enum CodingKeys: String, CodingKey {
case pk
case fullName = "full_name"
case username
case profilePicURL = "profile_pic_url"
}
}
Read the comments I added to the code decoding will not code a key that's not added to the struct
so commenting out position
will have no issue also, the hierarchy of it should be like this now I added a userNoPositions
computed value in response to give array of users easily.阅读我添加到代码中的注释解码不会对未添加到
struct
中的键进行编码,因此注释掉position
也没有问题,它的层次结构现在应该是这样的我添加了一个userNoPositions
计算值以响应给数组用户轻松。
Simply to access the array without positions简单地访问没有位置的数组
var resp = try! JSONDecoder().decode(Response.self, from: encoded) // encoded is the data from json
print(resp.userNoPositions) // the array
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.