微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

SwiftUI macOS JSON在Codable类中转换

如何解决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 举报,一经查实,本站将立刻删除。