【问题标题】:SwiftUI macOS JSON convert in class CodableSwiftUI macOS JSON 在 Codable 类中转换
【发布时间】:2020-08-29 20:06:15
【问题描述】:

我从 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)
}

问题是在数组 users 里面,它包含一个对象,这个对象包含两个元素一个位置属性,然后是用户对象。

我认为我做错的是获取用户对象。

谁能帮帮我?

编辑:

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)
        }

【问题讨论】:

  • 你要不要这个职位?
  • 我不要职位,只要用户信息。
  • 查看我添加的答案

标签: json swift swiftui fetch


【解决方案1】:

你可以试试这个。

    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"
    }
}

阅读我添加到代码解码中的 cmets 不会对未添加到 struct 的密钥进行编码,因此注释掉 position 也没有问题,它的层次结构现在应该是这样我添加了一个 @ 987654325@ 计算值以响应用户数组。
只需访问没有位置的数组

var resp =  try! JSONDecoder().decode(Response.self, from: encoded)  // encoded is the data from json   
print(resp.userNoPositions) // the array 

【讨论】:

  • 我收到以下错误:初始化程序 'init (_: rowContent :)' 要求 'UserWPosition' 符合 'Identifiable'
  • 你在做什么?我多次测试了该代码@Paul
  • @Paul 不再需要这个let users = results.users?.map { $0.user } 用户变量response.userNoPositions
  • 不知道自己做错了什么,这是原码:pastebin.com/xdcLgmzf
  • 我正在尝试两种解决方案,但我做错了。
【解决方案2】:

你需要一个额外的结构来保存用户类型

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, full_name, username, profile_pic_url
    }
}

解码时,您可以使用map 函数提取用户数组

do {
    let results = try JSONDecoder().decode(Response.self, from: data)
    let users = results.users?.map { $0.user }
    ....

请注意,我从 class 更改为 struct 因为 struct 更适合这个,但 class 也可以工作。我也想知道为什么users 属性是可选的,我没有改变它但是数组真的可以为零吗?

【讨论】:

  • 我按照你的指示做了,你可以在帖子中看到它,但我收到以下错误:初始化程序'init(_:rowContent :)'要求'用户'符合'可识别'在名单上(...)
  • 不知道自己做错了什么,这是原码:pastebin.com/xdcLgmzf
  • 我按照您的指示制作了用户结构,我收到以下错误:类型“用户”不符合协议“可识别”
  • 经过多次尝试后它最终不起作用,它似乎已经解决了这样的问题:var id: UUID {return UUID ()},我不明白为什么。
猜你喜欢
  • 2019-07-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-29
相关资源
最近更新 更多