可分解的嵌套数据,而无需在Swift中创建其他类 [英] Decodable nested data without creating additional class in Swift

查看:80
本文介绍了可分解的嵌套数据,而无需在Swift中创建其他类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是iOS开发的新手,所以请提前回答愚蠢的问题. 我有这样的json:

I'm new in iOS development, so sorry for stupid question in advance. I have json like this:

{
   "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,这是我的代码不起作用:)

I want to convert this to class which will contain just likesCount, commentsCount, repostsCount but without creating separate classes for comments, likes, reposts. I'm using Decodable for this and here is my code which doesn't work :)

代码:

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不存在,所以没有相关值.

The error is very clear, there are no values for associate keys likes.count as the key not exists.

使用

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

,然后尝试container.decodeIfPresent(:_)检查密钥是否存在或是否分配空值.

and try container.decodeIfPresent(:_) to check for key exists or if not assign empty value.

代码:

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

这篇关于可分解的嵌套数据,而无需在Swift中创建其他类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆