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

问题描述

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

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

奇怪的是,它并不总是出现,我可以打开 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()
    }
}

电影详情视图:

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

解决方法

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

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
}

,

我终于找到了导致错误的原因。对于电影模型中的 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
    //...
}

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