【问题标题】:Do I have to account for every case of my enum Coding Keys?我是否必须考虑我的枚举编码密钥的每种情况?
【发布时间】:2020-11-09 20:06:17
【问题描述】:

我有 3 个不同的 URL 用于获取我的 JSON:2 个使用“sn-p”参数,1 个不使用。第三个崩溃告诉我它没有“sn-p”参数,但前两个没有“统计”参数并且不会崩溃?

网址 1:“https://www.googleapis.com/youtube/v3/search?part=sn-p&channelId=(channelID)&maxResults=10&order=viewCount&key=(Constant.API_KEY)”

网址 2:“https://www.googleapis.com/youtube/v3/channels?part=sn-p&forUsername=(channelName)&key=(Constant.API_KEY)”

网址 3:“https://www.googleapis.com/youtube/v3/videos?part=statistics&id=(videoID)&key=(Constant.API_KEY)”

值得注意的是,我已经确认我正在获取 JSON,但它只是在涉及模型时崩溃。

struct Video: Identifiable, Decodable {
    
    var id = UUID()
    var title = ""
    var thumbnail = ""
    var videoID = ""
    var publishedDate = ""
    var youtuber = ""
    
    var viewCount = ""
    var watched = false

    enum CodingKeys: String, CodingKey {
        
        case snippet
        case thumbnails
        case high
        case id
        case statistics
        
        case videoID = "videoId"
        case title
        case thumbnail = "url"
        case publishedDate = "publishedAt"
        case youtuber = "channelTitle"
        case viewCount
    }
    
    init (from decoder: Decoder) throws {
        
        let container =  try decoder.container(keyedBy: CodingKeys.self)
        let snippetContainer = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .snippet)
        let thumbnailsContainer = try snippetContainer.nestedContainer(keyedBy: CodingKeys.self, forKey: .thumbnails)
        let highContainer = try thumbnailsContainer.nestedContainer(keyedBy: CodingKeys.self, forKey: .high)
        let idContainer = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .id)
        let statisticsContainer = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .statistics)
        
        self.title = try snippetContainer.decode(String.self, forKey: .title)
        self.thumbnail = try highContainer.decode(String.self, forKey: .thumbnail)
        self.videoID = try idContainer.decode(String.self, forKey: .videoID)
        self.publishedDate = try snippetContainer.decode(String.self, forKey: .publishedDate)
        self.youtuber = try snippetContainer.decode(String.self, forKey: .youtuber)
        self.viewCount = try statisticsContainer.decode(String.self, forKey: .viewCount)
        
    }
}

Solution:

Used the “if container.contains(CodingKeys.statistics)” method, problem solved.

【问题讨论】:

  • 您需要提供一个可重现性最低的示例,否则会导致您在下面的答案中看到的那种来回。您收到的 JSON 有哪些变化(请从 JSON/模型中删除任何不相关的内容)

标签: json swift enums decodable


【解决方案1】:

您的问题可以通过简单地将两个容器下的属性设置为可选来解决。另外,使用decodeIfPresent 方法解码值。

struct Video: Identifiable, Decodable {

    var id = UUID()
    var watched = false
    var videoID, title, thumbnail, youtuber, viewCount, publishedDate: String?

    enum CodingKeys: String, CodingKey {

        case snippet
        case thumbnails
        case high
        case id
        case statistics

        case videoID = "videoId"
        case title
        case thumbnail = "url"
        case publishedDate = "publishedAt"
        case youtuber = "channelTitle"
        case viewCount
    }

    init (from decoder: Decoder) throws {

        let container =  try decoder.container(keyedBy: CodingKeys.self)
        let snippetContainer = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .snippet)
        let thumbnailsContainer = try snippetContainer.nestedContainer(keyedBy: CodingKeys.self, forKey: .thumbnails)
        let highContainer = try thumbnailsContainer.nestedContainer(keyedBy: CodingKeys.self, forKey: .high)
        let idContainer = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .id)
        let statisticsContainer = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .statistics)

        self.title = try snippetContainer.decodeIfPresent(String.self, forKey: .title)
        self.thumbnail = try highContainer.decodeIfPresent(String.self, forKey: .thumbnail)
        self.videoID = try idContainer.decodeIfPresent(String.self, forKey: .videoID)
        self.publishedDate = try snippetContainer.decodeIfPresent(String.self, forKey: .publishedDate)
        self.youtuber = try snippetContainer.decodeIfPresent(String.self, forKey: .youtuber)
        self.viewCount = try statisticsContainer.decodeIfPresent(String.self, forKey: .viewCount)
    }
}

【讨论】:

  • 我得到了同样的结果。如果可能的话,我将不得不将这些枚举案例设为可选?
  • 还是什么都没有,我开始玩decodeIfPresent,感觉离我越来越近了。当我运行 URL 3 时,我得到“没有找到键 CodingKeys 的值(stringValue:\”sn-p\”,intValue:nil)”,当我运行 URL 1 时,我得到“没有找到键 CodingKeys 的值(stringValue:\”统计数据\", intValue: nil)"
  • 仍然没有。通过逐行注释/取消注释的更多故障排除表明,问题在于我将统计信息(或 sn-p)作为我的枚举中的键。一旦它尝试访问容器,我就完成了。我什至没有到达“decodeIfPresent”部分,它在那之前就停止了
  • 在您的问题中发布您尝试解码的JSON
  • 找到了一个修复,发布在我的帖子中。感谢您的尝试
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-23
  • 2011-10-30
  • 1970-01-01
  • 1970-01-01
  • 2010-12-30
  • 1970-01-01
相关资源
最近更新 更多