ios - 无需在 Swift 中创建附加类即可解码嵌套数据

标签 ios json swift decodable

我是 iOS 开发的新手,很抱歉提前提出愚蠢的问题。 我有这样的 json:

{
   "type":"post",
   "comments":{
      "count":0,
      "can_post":1
   },
   "likes":{
      "count":0,
      "user_likes":0,
      "can_like":1,
      "can_publish":1
   },
   "reposts":{
      "count":0,
      "user_reposted":0
   }
}

我想将其转换为仅包含 likesCount、commentsCount、repostsCount 的类,但不为 commentslikesreposts 创建单独的类>。我正在为此使用 Decodable,这是我的代码,它不起作用:)

代码:

final class FeedItem: Decodable {
    enum Keys: String, CodingKey {
        case type,
        likes = "likes.count",
        comments = "comments.count",
        reposts = "reposts.count"
    }

    let type: String
    var likes = 0
    var comments = 0
    var reposts = 0

    required convenience init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: Keys.self)
        let type = try container.decode(String.self, forKey: .type)
        let likes = try container.decode(Int.self, forKey: .likes)
        let comments = try container.decode(Int.self, forKey: .comments)
        let reposts = try container.decode(Int.self, forKey: .reposts)
        self.init(type: type, likes: likes, comments: comments, reposts: reposts)
    }

    init(type: String,
         likes: Int,
         comments: Int,
         reposts: Int) {
        self.type = type
        self.likes = likes
        self.comments = comments
        self.reposts = reposts
    }
}

错误:

"No value associated with key Keys(stringValue: \"likes.count\", intValue: nil) (\"likes.count\")."

最佳答案

错误很明显,关联键 likes.count 没有值,因为键不存在。

使用

let container = try decoder.container(keyedBy: CodingKeys.self)

并尝试 container.decodeIfPresent(:_) 检查键是否存在,如果不存在则分配空值。

代码:

struct FeedItem: Codable {

    let type: String
    let commentsCount: Int
    let canPostComment: Int
    let likesCount: Int
    let userLikes: Int
    let canLike: Int
    let canPublish: Int
    let repostsCount: Int
    let userReposted: Int

    enum CodingKeys: String, CodingKey {
        case type = "type"
        case comments = "comments"
        case likes = "likes"
        case reposts = "reposts"
        case count = "count"
        case canPost = "can_post"
        case userLikes = "user_likes"
        case canLike = "can_like"
        case canPublish = "can_publish"
        case userReposted = "user_reposted"
    }

    init(from decoder: Decoder) throws {

        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.type = try container.decodeIfPresent(String.self, forKey: .type) ?? ""

        let comments = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .comments)
        self.commentsCount = try comments.decodeIfPresent(Int.self, forKey: .count) ?? 0
        self.canPostComment = try comments.decodeIfPresent(Int.self, forKey: .canPost) ?? 0

        let likes = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .likes)
        self.likesCount = try likes.decodeIfPresent(Int.self, forKey: .count) ?? 0
        self.userLikes = try likes.decodeIfPresent(Int.self, forKey: .userLikes) ?? 0
        self.canLike = try likes.decodeIfPresent(Int.self, forKey: .canLike) ?? 0
        self.canPublish = try likes.decodeIfPresent(Int.self, forKey: .canPublish) ?? 0

        let reposts = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .reposts)
        self.repostsCount = try reposts.decodeIfPresent(Int.self, forKey: .count) ?? 0
        self.userReposted = try reposts.decodeIfPresent(Int.self, forKey: .userReposted) ?? 0
    }

    func encode(to encoder: Encoder) throws {

        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(type, forKey: .type)

        var comments = container.nestedContainer(keyedBy: CodingKeys.self, forKey: .comments)
        try comments.encode(commentsCount, forKey: .count)
        try comments.encode(canPostComment, forKey: .canPost)

        var likes = container.nestedContainer(keyedBy: CodingKeys.self, forKey: .likes)
        try likes.encode(likesCount, forKey: .count)
        try likes.encode(userLikes, forKey: .userLikes)
        try likes.encode(canLike, forKey: .canLike)
        try likes.encode(canPublish, forKey: .canPublish)

        var reposts = container.nestedContainer(keyedBy: CodingKeys.self, forKey: .reposts)
        try reposts.encode(repostsCount, forKey: .count)
        try reposts.encode(userReposted, forKey: .userReposted)
    }
}

数据读取:

let data = //Your JSON data from API
let jsonData = try JSONDecoder().decode(FeedItem.self, from: data)
print("\(jsonData.type) \(jsonData.canLike)")

关于ios - 无需在 Swift 中创建附加类即可解码嵌套数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53241576/

相关文章:

ios - 自动布局的基本理解

ios - navigationController 在 Swift 上意外发现 nil

Swift Firebase 按最后 10 个排序,然后显示 10 个新值

swift - 如何快速计算跨越两天的两次之间的正确时间间隔?

ios - 如何使用 OpenCV 在 iOS 应用程序中检测面部侧 View 左耳、侧 View Nose 、侧 View 嘴?

ios - 使用自定义对象 ios 键入 Cast

json - 使用 Circe 自定义编解码器将 json 解码为案例类列表

android - 如何在 Android 中创建 JSON

json - 为多个目标主机创建 ansible list

ios - 制作一个 UITableView "sticky to the bottom"