我正在尝试使用tmdb api,当我发出请求时,它告诉我我的信息格式错误。
有人知道为什么吗?我将我的代码留在下面。
import Foundation
struct result:Codable{
public let page: Int?
public let totalResults: Int?
public let totalPages: Int?
var results:[ModelAPI]?
}
struct ModelAPI: Codable{
var id:Int?
var adult: Bool?
var backdroppath: String?
var belongstocollection:String?
var budget:Double?
var genres: [genress]?
var homepage:String?
var imdbid:String?
var originallanguage: String?
var originaltitle: String?
var overview:String?
var popularity:Double?
var posterpath:String?
var productioncompanies: [prodCompanies]?
var porductioncountries: [productionCountries]?
var releasedate:String?
var revenue: Int?
var runtime:Int?
var spokenlanguages:String?
var status:String?
var tagline:String?
var title:String?
var video:Bool?
var voteaverage:Int?
var votecount:Int?
enum CodingKeys: String, CodingKey {
case spokenlanguages = "spoken_languages"
case imdbid = "imdb_id"
case voteaverage = "vote_average"
case votecount = "vote_count"
case productioncompanies = "production_companies"
case porductioncountries = "porduction_countries"
case releasedate = "release_date"
case posterpath = "poster_path"
case originaltitle = "original_title"
case originallanguage = "original_language"
case backdroppath = "backdrop_path"
case belongstocollection = "belongs_to_collection"
case genres = "genres"
case id = "id"
case adult = "adult"
case budget = "budget"
case homepage = "homepage"
case overview = "overview"
case popularity = "popularity"
case revenue = "revenue"
case runtime = "runtime"
case status = "status"
case tagline = "tagline"
case title = "title"
case video = "video"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
if let id = try container.decode(Int?.self, forKey:.id ) {
self.id = id
}
if let adult = try container.decode(Bool?.self, forKey:.adult ) {
self.adult = adult
}
if let backdroppath = try container.decode(String?.self, forKey:.adult ) {
self.backdroppath = backdroppath
}
if let belongstocollection = try container.decode(String?.self, forKey:.belongstocollection ) {
self.belongstocollection = belongstocollection
}
if let budget = try container.decode(Double?.self, forKey:.budget ) {
self.budget = budget
}
if let genres = try container.decode([genress]?.self, forKey:.genres ) {
self.genres = genres
}
if let homepage = try container.decode(String?.self, forKey:.homepage ) {
self.homepage = homepage
}
if let imdbid = try container.decode(String?.self, forKey:.imdbid ) {
self.imdbid = imdbid
}
if let originallanguage = try container.decode(String?.self, forKey:.originallanguage ) {
self.originallanguage = originallanguage
}
if let originaltitle = try container.decode(String?.self, forKey:.originaltitle ) {
self.originaltitle = originaltitle
}
if let overview = try container.decode(String?.self, forKey:.overview ) {
self.overview = overview
}
if let popularity = try container.decode(Double?.self, forKey:.popularity ) {
self.popularity = popularity}
if let posterpath = try container.decode(String?.self, forKey:.posterpath ) {
self.posterpath = posterpath
}
if let productioncompanies = try container.decode([prodCompanies]?.self, forKey:.productioncompanies ) {
self.productioncompanies = productioncompanies
}
if let porductioncountries = try container.decode([productionCountries]?.self, forKey:.porductioncountries ) {
self.porductioncountries = porductioncountries
}
if let releasedate = try container.decode(String?.self, forKey:.releasedate ) {
self.releasedate = releasedate
}
if let revenue = try container.decode(Int?.self, forKey:.revenue ) {
self.revenue = revenue
}
if let runtime = try container.decode(Int?.self, forKey:.runtime ) {
self.runtime = runtime
}
if let spokenlanguages = try container.decode(String?.self, forKey:.spokenlanguages ) {
self.spokenlanguages = spokenlanguages
}
if let status = try container.decode(String?.self, forKey:.status ) {
self.status = status
}
if let tagline = try container.decode(String?.self, forKey:.tagline ) {
self.tagline = tagline
}
if let title = try container.decode(String?.self, forKey:.title ) {
self.title = title
}
if let video = try container.decode(Bool?.self, forKey:.video ) {
self.video = video
}
if let voteaverage = try container.decode(Int?.self, forKey:.voteaverage ) {
self.voteaverage = voteaverage
}
if let votecount = try container.decode(Int?.self, forKey:.votecount ) {
self.votecount = votecount
}
}
}
struct languages: Codable{
var englishname:String?
var iso6391:String?
var name:String?
enum CodingKeys: String, CodingKey {
case englishname = "english_name"
case iso6391 = "iso_639_1"
case name = "name"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
if let englishname = try container.decode(String?.self, forKey:.englishname ) {
self.englishname = englishname
}
if let iso6391 = try container.decode(String?.self, forKey:.iso6391 ) {
self.iso6391 = iso6391
}
if let name = try container.decode(String?.self, forKey:.name ) {
self.name = name
}
}
}
struct productionCountries:Codable{
var iso31661:String?
var name:String?
enum CodingKeys: String, CodingKey {
case iso31661 = "iso_3166_1"
case name = "name"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
if let iso31661 = try container.decode(String?.self, forKey:.iso31661 ) {
self.iso31661 = iso31661
}
if let name = try container.decode(String?.self, forKey:.name ) {
self.name = name
}
}
}
struct prodCompanies:Codable{
var id: Int?
var logopath:String?
var name:String?
var origincountry:String?
enum CodingKeys: String, CodingKey {
case origincountry = "origin_country"
case logopath = "logo_path"
case id = "id"
case name = "name"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
if let origincountry = try container.decode(String?.self, forKey:.origincountry ) {
self.origincountry = origincountry
}
if let name = try container.decode(String?.self, forKey:.name ) {
self.name = name
}
if let id = try container.decode(Int?.self, forKey:.id ) {
self.id = id
}
if let logopath = try container.decode(String?.self, forKey:.logopath ) {
self.logopath = logopath
}
}
}
struct genress: Codable {
var id: Int?
var name:String?
enum CodingKeys: String, CodingKey {
case id = "id"
case name = "name"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
if let name = try container.decode(String?.self, forKey:.name ) {
self.name = name
}
if let id = try container.decode(Int?.self, forKey:.id ) {
self.id = id
}
}
}
我做了很多代码,因为我发现很多时候jsondecoder不支持编码键。
同样在下面,我离开我的视图控制器
class ViewController: UIViewController {
@IBOutlet var movieCollection: UICollectionView!
var delegate:API?
var task = URLSession.shared
var tmdbAPI = "https://api.themoviedb.org/3/movie/upcoming?api_key="
var APIKey = "b64d7f3ead34bfc2d9ade2eb40d81e37"
override func viewDidLoad() {
super.viewDidLoad()
movieCollection.delegate = self
movieCollection.dataSource = self
getAPI()
}
func getAPI(){
let URLString = "\(tmdbAPI)"+"\(APIKey)" + "&language=en-US"
let url = URL(string: URLString)!
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue( "Bearer eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJiNjRkN2YzZWFkMzRiZmMyZDlhZGUyZWI0MGQ4MWUzNyIsInN1YiI6IjVmYmYyZDUyYTNkMDI3MDA0MGJkNjcyNiIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.NLq6xkhLx7uDI6SwyaFrGOcIi3yidJOLK76tmR7a6O8", forHTTPHeaderField: "Authorization")
task.dataTask(with: request) { (data, response, erro) in
guard let datos = data else {
self.delegate?.APIError(error:.endPointError)
return
}
do{
let json = try JSONDecoder().decode(result.self, from: datos)
debugPrint("json",json)
}catch {
debugPrint(error.localizedDescription)
self.delegate?.APIError(error: .errorResponse)
}
}.resume()
}
}
建立模型的方式是错误的,如果没有nil或错误,则不会分配默认值。因此解码总是失败。
尝试以这种方式创建模型或使用在线工具:
struct ResultRootModel : Codable {
let results : [ResultsModel]?
let page : Int?
let total_results : Int?
let total_pages : Int?
enum CodingKeys: String, CodingKey {
case results = "results"
case page = "page"
case total_results = "total_results"
case total_pages = "total_pages"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
results = try values.decodeIfPresent([ResultsModel].self, forKey: .results)
page = try values.decodeIfPresent(Int.self, forKey: .page)
total_results = try values.decodeIfPresent(Int.self, forKey: .total_results)
total_pages = try values.decodeIfPresent(Int.self, forKey: .total_pages)
}
}
struct ResultsModel : Codable {
let video : Bool?
let vote_average : Double?
let popularity : Double?
let vote_count : Int?
let release_date : String?
let adult : Bool?
let backdrop_path : String?
let overview : String?
let genre_ids : [Int]?
let title : String?
let original_language : String?
let original_title : String?
let poster_path : String?
let id : Int?
enum CodingKeys: String, CodingKey {
case video = "video"
case vote_average = "vote_average"
case popularity = "popularity"
case vote_count = "vote_count"
case release_date = "release_date"
case adult = "adult"
case backdrop_path = "backdrop_path"
case overview = "overview"
case genre_ids = "genre_ids"
case title = "title"
case original_language = "original_language"
case original_title = "original_title"
case poster_path = "poster_path"
case id = "id"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
video = try values.decodeIfPresent(Bool.self, forKey: .video)
vote_average = try values.decodeIfPresent(Double.self, forKey: .vote_average)
popularity = try values.decodeIfPresent(Double.self, forKey: .popularity)
vote_count = try values.decodeIfPresent(Int.self, forKey: .vote_count)
release_date = try values.decodeIfPresent(String.self, forKey: .release_date)
adult = try values.decodeIfPresent(Bool.self, forKey: .adult)
backdrop_path = try values.decodeIfPresent(String.self, forKey: .backdrop_path)
overview = try values.decodeIfPresent(String.self, forKey: .overview)
genre_ids = try values.decodeIfPresent([Int].self, forKey: .genre_ids)
title = try values.decodeIfPresent(String.self, forKey: .title)
original_language = try values.decodeIfPresent(String.self, forKey: .original_language)
original_title = try values.decodeIfPresent(String.self, forKey: .original_title)
poster_path = try values.decodeIfPresent(String.self, forKey: .poster_path)
id = try values.decodeIfPresent(Int.self, forKey: .id)
}
}
改变这条线
let json = try JSONDecoder().decode(result.self, from: datos)
至
let json = try JSONDecoder().decode(ResultRootModel.self, from: datos)
一些建议:
以大写字母开始结构/类名
打印print(error)
代替debugPrint(error.localizedDescription)
它会给更多的解释上的错误,如下面:
keyNotFound(CodingKeys(stringValue: "budget", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "results", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: \"budget\", intValue: nil) (\"budget\").", underlyingError: nil))