JSON解码时出错:Swift.DecodingError.keyNotFound(CodingKeys(stringValue:“cast”,intValue:nil)

Posted

技术标签:

【中文标题】JSON解码时出错:Swift.DecodingError.keyNotFound(CodingKeys(stringValue:“cast”,intValue:nil)【英文标题】:Error while JSON decoding: Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "cast", intValue: nil) 【发布时间】:2021-03-02 16:08:37 【问题描述】:

在尝试解码 JSON 时,我遇到了一个错误:

致命错误:“试试!”表达式意外引发错误: Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "cast", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription:“没有与键关联的值 CodingKeys(stringValue: "cast", intValue: nil) ("cast").", 底层错误:无))

奇怪的是,它并不总是出现,我可以打开MovieDetailsView几次而不会出现错误,但出现的次数更多。可能是什么问题?

数据模型:

struct MovieCreditResponse: Codable 
    let cast: [MovieCast]


struct MovieCast: Identifiable, Codable 
    let id: Int
    let character: String
    let name: String
    let profilePath: String?

我在这里获取数据:

class TMDbApi 
    //...

    func getMovieCredits(movieID: String, completion:@escaping (MovieCreditResponse) -> ())
        guard let url = URL(string: "https://api.themoviedb.org/3/movie/\(movieID)/credits?api_key=<api_key>") else  return 
        URLSession.shared.dataTask(with: url)  (data, _, _) in
            let movies = try! JSONDecoder().decode(MovieCreditResponse.self, from: data!) //ERROR IS HERE
            
            DispatchQueue.main.async 
                completion(movies)
            
        
        .resume()
    

MovieDetailsView:

struct MovieDetailsView: View 
    var movie: Movie
    
    @State var casts: [MovieCast] = []
    
    var body: some View 
        VStack
            MoviePosterView(posterPath: movie.posterPath!)
            List
                ForEach(casts) cast in
                    Text(cast.name)
                
            
        .onAppear
            TMDbApi().getMovieCredits(movieID: movie.id.uuidString) data in
                self.casts = data.cast
            
        
    

内容视图:

struct ContentView: View 
    @State var movies: [Movie] = []
    
    var body: some View 
        NavigationView
            List 
                ForEach(movies)  movie in
                    NavigationLink(destination: MovieDetailsView(movie: movie))
                        //...
                    
                
            .onAppear()
                TMDbApi().getMovies data in
                    self.movies = data.results
                
                //...
            
            .navigationTitle("Movies App")
        
    

【问题讨论】:

如果我不得不猜测,您得到的响应并不总是包含 cast 值,并且由于您正在强制尝试(您不应该这样做,您应该处理而是错误),您的应用程序正在崩溃。您是否尝试过查看解码失败时得到的响应? 另外你应该重新生成你的 API 密钥,因为你已经把它粘贴到这里了。 为什么不查看documentation? @JoakimDanielson 我阅读了文档documentation。在我看来我什么都照着做,也许我错了 是的,我的错,我错过了你网址的最后一部分,所以我检查了错误的端点。我建议使用String(data: data, encoding: .utf8) 打印数据,看看你真正得到了什么 【参考方案1】:

最后我找到了导致错误的原因。我在电影模型中使用UUID 类型而不是Int 作为id 属性(这是我在URL 中用于查询电影演员的ID)。因此,在我的请求中,电影 ID 的格式为“F77A9A5D-1D89-4740-9B0D-CB04E75041C5”而不是“278”。有趣的是,有时这不会导致错误,这让我很困惑(我仍然不知道为什么有时会这样)

所以,我换了

struct Movie: Identifiable, Codable
    let id = UUID()
    //...

struct Movie: Identifiable, Codable
    let id: Int
    //...

感谢所有帮助我找到解决方案的人

【讨论】:

为了在未来帮助您,您可以粘贴您的 json here,它将生成正确的结构和解码代码。此外,在您的问题中添加一些(示例)json 可能很有用。【参考方案2】:

如果您的响应可能包含错误(确实会发生错误!),您的应用应该知道并处理它。

struct MovieCreditResponse: Codable 
    let success : Bool
    let status_code : Int
    let status_message : String?
    let cast: [MovieCast]?

然后,当您收到响应时,检查是否成功并让您的应用处理错误:

do 
    guard let d = data else  
        // handle null data error 
    
    let responseObject = try JSONDecoder().decode(MovieCreditResponse.self, from: d) 
    if responseObject.success 
        guard let cast = responseObject.cast as? [MovieCast] else 
            // handle error of null cast here
        
        // this is the happy path: do your thing
     else 
        if let errorMessage = responseObject.status_message 
            // handle the case of an identified error
            handleError(errorMessage)
         else 
            // handle the case where something went wrong and you don't know what
        
    
 catch 
    // handle decoding error here


【讨论】:

这个答案基于一个不正确的假设,当问题是由于错误而返回的完全不同的消息时,有时可能会丢失演员表。您的第一个选项可能有效,但会隐藏实际错误,而第二个选项将与当前代码一样失败。 哦,这是一个很好的观点,我在看到原始 JSON 之前写了这个,它“在首屏之下”。

以上是关于JSON解码时出错:Swift.DecodingError.keyNotFound(CodingKeys(stringValue:“cast”,intValue:nil)的主要内容,如果未能解决你的问题,请参考以下文章

解码 JSON 时出错 - keyNotFound(CodingKeys

Swift4:从文件中解码 json 时出错

JSON解码时出错:Swift.DecodingError.keyNotFound(CodingKeys(stringValue:“cast”,intValue:nil)

Apollo graphQL:在 iOS swift 中使用自定义标量时解码数组时出错

url解码和发布数据后出错

json.load 加载带有拉丁字符的文件时出错