如何解决SwiftUI macOS JSON在Codable类中转换
我从api调用中获取了以下json,但无法快速构建适当的结构,然后将数据作为数组获取。
JSON:
{
"status":"ok","users":[
{
"position":0,"user":{
"pk":"","full_name":"","username":"","profile_pic_url":""
}
},...
]
}
迅速:
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()
}
}
代码:
@Observedobject var fetch = Fetch(url: "")
List(fetch.results) { user in
UserItem(user: user)
}
问题是在数组用户内部,它包含一个对象,该对象包含两个元素,即位置属性和用户对象。
有人可以帮我吗?
编辑:
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,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)
}
解决方法
您需要一个额外的结构来保存用户类型
struct UserType: Codable {
let position: Int
let user: User
}
表示顶部类型变为
struct Response: Codable {
let status: String
let users: [UserType]?
}
您还需要更改CodingKeys
枚举,因为它应该只包含表示该枚举可以写为的属性名称
enum CodingKeys: String,CodingKey {
case pk,full_name,username,profile_pic_url
}
为完整起见,这里是完整的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,profile_pic_url
}
}
在解码时,您可以使用map
函数提取用户数组
do {
let results = try JSONDecoder().decode(Response.self,from: data)
let users = results.users?.map { $0.user }
....
请注意,我从类更改为struct,因为struct更适合于此,但类也适用。我也想知道为什么users
属性是可选的,我没有更改,但是数组真的可以为零吗?
您可以尝试一下。
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,profilePicURL: String
enum CodingKeys: String,CodingKey {
case pk
case fullName = "full_name"
case username
case profilePicURL = "profile_pic_url"
}
}
阅读我添加到代码解码中的注释将不会对未添加到struct
的键进行编码,因此注释掉position
也没有问题,它的层次结构现在应该像这样我添加了一个userNoPositions
计算值,以方便地给用户数组。
只需访问没有位置的数组
var resp = try! JSONDecoder().decode(Response.self,from: encoded) // encoded is the data from json
print(resp.userNoPositions) // the array
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。