代码之家  ›  专栏  ›  技术社区  ›  Noam Kurtzer

从NewsCatcher API解析JSON时出现Swift“无与密钥编码密钥关联的值”错误

  •  0
  • Noam Kurtzer  · 技术社区  · 3 年前

    在斯威夫特还是新的。我已经搜索了很多关于这个主题的类似问题,但由于某种原因,我仍然无法确定问题出在我的结构是如何构建的,或者我做错了什么。谢谢你的帮助!

    我在swift应用程序中使用newswatcher api,获取的数据如下所示:

    {
        "status": "ok",
        "total_hits": 10000,
        "page": 1,
        "total_pages": 10000,
        "page_size": 1,
        "articles": [
            {
                "title": "Pizza Pizza has teamed up with Mattel for the ultimate game night combo",
                "author": null,
                "published_date": "2022-03-18 20:34:17",
                "published_date_precision": "full",
                "link": "https://dailyhive.com/vancouver/pizza-pizza-mattel-canada-uno",
                "clean_url": "dailyhive.com",
                "excerpt": "Pizza and game nights are a match made in heaven. Pizza Pizza has partnered with Mattel Canada for the ultimate package deal.",
                "summary": "Pizza and game nights are a match made in heaven — even Pizza Pizza knows that. The Canadian chain has partnered with Mattel Canada for the ultimate package deal.\nReturning for another year is the pizza chain's UNO collab but this time it features a new limited-edition Pizza Pizza or Pizza 73 branded UNO deck with every featured UNO combo purchase.\nThe decks feature pizza art and a surprise bonus offer too.\n\n \nView this post on Instagram\n A post shared by Pizza Pizza (@pizzapizzaltd)\n\n 'For over 50 years, UNO has become a staple at game nights across the country, bringing families and friends together through gameplay,' said Jennifer Gileno, Head of Licensing and Retail Development for Mattel Canada.",
                "rights": null,
                "rank": 9543,
                "topic": "news",
                "country": "CA",
                "language": "en",
                "authors": [],
                "media": "https://images.dailyhive.com/20220318132250/pizza-pizza-uno-500x256.jpg",
                "is_opinion": false,
                "twitter_account": "https://dailyhive.com/vancouver/pizza-pizza-mattel-canada-uno",
                "_score": 14.017945,
                "_id": "feca5f5fe473e561bf0b8c11b01b87bf"
            }
        ],
        "user_input": {
            "q": "pizza",
            "search_in": [
                "title_summary"
            ],
            "lang": null,
            "not_lang": null,
            "countries": null,
            "not_countries": null,
            "from": "2022-03-15 00:00:00",
            "to": null,
            "ranked_only": "True",
            "from_rank": null,
            "to_rank": null,
            "sort_by": "relevancy",
            "page": 1,
            "size": 1,
            "sources": null,
            "not_sources": null,
            "topic": null,
            "published_date_precision": null
        }
    }
    

    为了解码数据,我创建了以下结构:

    struct ArticleModel: Codable {
        
        let totalPages: Int
        let articles: [Articles]
        let numOfResults: Int
        
        enum CodingKeys: String, CodingKey {
            case totalPages = "total_pages"
            case articles = "articles"
            case numOfResults = "total_hits"
        }
    }
    
    struct Articles: Codable {
        
        let id: String
        let articleTitle: String
        let date: String
        let url: String
        let content: String
        let author: String?
        let topic: String
        let imageUrl: String?
        
        enum CodingKeys: String, CodingKey {
            case id = "_id"
            case articleTitle = "title"
            case content = "summary"
            case author = "author"
            case url = "link"
            case date = "published_date"
            case topic = "topic"
            case imageUrl = "media"
        }
    }
    

    我在我的应用程序中使用分页,我的初始抓取工作正常,没有问题。然而,当向下滚动到UITableView的底部时,我触发了另一个获取请求(对于下一批数据,即第2页的数据),我在控制台中收到以下错误:

    keyNotFound(编码键(stringValue:“总页数”,intValue:无),Swift。解码错误。Context(codingPath:[],debugDescription:“没有与键CodingKeys关联的值(stringValue:“总计页面”,intValue:nil)(“总计页面”)”,参考误差:零)

    分页工作正常,数据批按原样检索。。但我不明白为什么这个错误会不断出现,为什么只有从第二次开始抓取时才会发生。

    编辑#1 :无论我取哪个查询或页面- total_pages 总是在结果中返回,并且总是有一个值。

    编辑#2 :我试着做了 总页数 可选,但控制台中的错误将更改为:

    keyNotFound(CodingKeys(stringValue:“articles”,intValue:nil),Swift。解码错误。Context(codingPath:[],debugDescription:“没有与键codingkey(stringValue:“articles”,intValue:nil)关联的值”(“articles”)”,参考误差:零) 这也没有任何意义,因为我在屏幕上看到了新的结果。。

    编辑#3 :这是我在第二页得到的回复- 来自邮递员:

    {
        "status": "ok",
        "total_hits": 10000,
        "page": 2,
        "total_pages": 10000,
        "page_size": 1,
        "articles": [
            {
                "title": "Broadway & Beyond Hosts Webinar on Anti-Racist Stage Management Practices",
                "author": "Raven Brunner",
                "published_date": "2022-03-21 17:17:43",
                "published_date_precision": "full",
                "link": "https://playbill.com/article/broadway-beyond-hosts-webinar-on-anti-racist-stage-management-practices",
                "clean_url": "playbill.com",
                "excerpt": "The webinar will be led by veteran stage managers Narda E. Alcorn and Lisa Porter.",
                "summary": "Education News Education News Education News Education News Theatre Alternatives Industry News Industry News Industry News Education News Education News Education News Education News Education News Education News Industry News Industry News Industry News Education News Education News Industry News Industry News Education News Education News Industry News Education News Industry News Education News Industry News Industry News Education News Education News Industry News Education News Industry New",
                "rights": "playbill.com",
                "rank": 5215,
                "topic": "entertainment",
                "country": "US",
                "language": "en",
                "authors": [
                    "Raven Brunner"
                ],
                "media": "https://assets.playbill.com/editorial/_1200x630_crop_center-center_82_none/Narda-E.-Alcorn-and-Lisa-Porter_HR.jpg?mtime=1647876883",
                "is_opinion": false,
                "twitter_account": "@playbill",
                "_score": 5.5872316,
                "_id": "7e297f463684c344e3bb9b70d6229fbf"
            }
        ],
        "user_input": {
            "q": "news",
            "search_in": [
                "title_summary"
            ],
            "lang": null,
            "not_lang": null,
            "countries": null,
            "not_countries": null,
            "from": "2022-03-15 00:00:00",
            "to": null,
            "ranked_only": "True",
            "from_rank": null,
            "to_rank": null,
            "sort_by": "relevancy",
            "page": 2,
            "size": 1,
            "sources": null,
            "not_sources": null,
            "topic": null,
            "published_date_precision": null
        }
    }
    

    从控制台:

    ArticleModel(totalPages: 10000, articles: [Dispatcher_Development.Articles(id: "7e297f463684c344e3bb9b70d6229fbf", articleTitle: "Broadway & Beyond Hosts Webinar on Anti-Racist Stage Management Practices", date: "2022-03-21 17:17:43", url: "https://playbill.com/article/broadway-beyond-hosts-webinar-on-anti-racist-stage-management-practices", content: "Education News Education News Education News Education News Theatre Alternatives Industry News Industry News Industry News Education News Education News Education News Education News Education News Education News Industry News Industry News Industry News Education News Education News Industry News Industry News Education News Education News Industry News Education News Industry News Education News Industry News Industry News Education News Education News Industry News Education News Industry New", author: Optional("Raven Brunner"), topic: "entertainment", imageUrl: Optional("https://assets.playbill.com/editorial/_1200x630_crop_center-center_82_none/Narda-E.-Alcorn-and-Lisa-Porter_HR.jpg?mtime=1647876883"))], numOfResults: 10000)
    

    以防万一——以下是我如何检测到用户一直向下滚动:

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
            
            let position = scrollView.contentOffset.y
            if position > (tableView.contentSize.height - 100 - scrollView.frame.size.height) {
                fetchNewsFromAPI() {
                    DispatchQueue.main.async {
                        self.tableView.tableFooterView = nil
                    }
                }
            }
        }
    

    这是负责获取数据的函数:

    func fetchNewsFromAPI(completionHandler: @escaping () -> ()) {
            
            let alamofireQuery = AlamofireManager(from: "\(Constants.apiCalls.newsUrl)?q=news&page_size=\(amountToFetch)&page=\(currentPaginationPage)")
            
            if !alamofireQuery.isPaginating && currentPaginationPage <= totalPaginationPages {
                alamofireQuery.executeGetQuery(){
                    (result: Result<ArticleModel,Error>) in
                    switch result {
                    case .success(let response):
                        self.currentPaginationPage += 1
                        self.totalPaginationPages = response.totalPages
                        
                        self.newsArray.append(contentsOf: response.articles)
                        DispatchQueue.main.async {
                            self.dataSource.models = self.newsArray
                            self.tableView.reloadData()
                        }
                    case .failure(let error):
                        print(error)
                    }
                    completionHandler()
                }
            }
        }
    

    这是我的Alamofire文件中的executeQuery函数:

    func executeGetQuery<T>(completion: @escaping (Result<T, Error>) -> Void) where T: Codable {
            isPaginating = true
            AF.request(url, method: .get, headers: headers).responseData(completionHandler: { response in
                do {
                    switch response.result {
                    case .success:
                        completion(.success(try JSONDecoder().decode(T.self, from: response.data ?? Data())))
                        self.isPaginating = false
                    case .failure(let error):
                        completion(.failure(error))
                    }
                } catch let error {
                    completion(.failure(error))
                    self.isPaginating = false
                }
            })
        }
    
    2 回复  |  直到 3 年前
        1
  •  0
  •   stoikokolev    3 年前

    我想到的是,你需要将totalPages解码为可选。

    let totalPages: Int?
    
        2
  •  -1
  •   iMoeNya    3 年前

    为什么只有从第二次开始时才会发生

    检查第二次响应的JSON数据。原因根据错误消息:

    keyNotFound(编码键(stringValue:“总页数”,intValue:无),Swift。解码错误。Context(codingPath:[],debugDescription:“没有与键CodingKeys关联的值(stringValue:“总计页面”,intValue:nil)(“总计页面”)”,参考误差:零)

    , total_pages 不见了。

    这可能是一个后端错误,这取决于 ArticleModel 没有一个 总页数 .

    如果是有意的,那么就做出决定 totalPages 可选:

    let totalPages: Int?