Warm tip: This article is reproduced from serverfault.com, please click

json-Swift,由于格式不正确,无法读取数据

(json - Swift, The data couldn’t be read because it isn’t in the correct format)

发布于 2020-11-28 03:42:53

我正在尝试使用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()
   
}

}

Questioner
Jael Ruvalcaba
Viewed
11
Pratik Prajapati 2020-11-28 12:37:58

建立模型的方式是错误的,如果没有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))