可分解的嵌套数据,而无需在Swift中创建其他类

时间:2018-11-10 17:29:23

标签: 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\")."

1 个答案:

答案 0 :(得分:2)

该错误非常明显,因为该键不存在,所以没有关联键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)")