JSON 解码器 无法读取数据,因为它的格式不正确

标签 json swiftui

我是新来的。不知何故,我能够理解如何做到这一点。
我在下面做,但它给出了错误 - 无法读取数据,因为它的格式不正确。有人可以帮助我吗?从过去的 4 天开始,我一直坚持这一点。我真的很感激。

import SwiftUI
import Foundation
import Combine

struct Movie: Decodable, Identifiable {

    var id: Int
    var video: String
    var vote_count: String
    var vote_average: String
    var title: String
    var release_date: String
    var original_language: String
    var original_title: String
}

struct MovieList: Decodable{
    var results: [Movie]

___________

class NetworkingManager : ObservableObject{
    var objectWillChange = PassthroughSubject<NetworkingManager, Never>()
    @Published var movies = [Movie]()

   init() {
      load()
   }

   func load(){
       let url = URL(string: "https://api.themoviedb.org/3/discover/movie?sort_by=popularity.desc&api_key=<HIDDEN>")!  

    URLSession.shared.dataTask(with: url){ (data, response, error) in

        do {
            if let d = data {
                let decodedLists = try JSONDecoder().decode([Movie].self, from: d)
                DispatchQueue.main.async {
                    self.movies = decodedLists
                }
            }else {
                print("No Data")
            }
        } catch {
            print (error.localizedDescription)
        }

            }.resume()

   }

} 

这是响应的样子:
{
  "page": 1,
  "results": [
    {
      "id": 419704,
      "video": false,
      "vote_count": 1141,
      "vote_average": 6.2,
      "title": "Ad Astra",
      "release_date": "2019-09-17",
      "original_language": "en",
      "original_title": "Ad Astra",
      "genre_ids": [
        878
      ],
      "backdrop_path": "/5BwqwxMEjeFtdknRV792Svo0K1v.jpg",
      "adult": false,
      "overview": "An astronaut travels to the outer edges of the solar system to find his father and unravel a mystery that threatens the survival of Earth. In doing so, he uncovers secrets which challenge the nature of human existence and our place in the cosmos.",
      "poster_path": "/xJUILftRf6TJxloOgrilOTJfeOn.jpg",
      "popularity": 227.167,
      "media_type": "movie"
    },
    ]
}

代码应该获取数据并将我创建的数组保存在其中。这样我就可以用它在前端显示。

最佳答案

我不得不为类似的项目使用完全相同的 API,这就是我的做法。

调用时:

let response = try JSONDecoder().decode(MovieResponse.self, from: data)

它需要匹配 JSON 响应返回的相同属性。

下面你会看到一个 MovieResponse结构体和 Movie类,它将列出 JSON 响应返回的所有属性和返回类型。

The type adopts Codable so that it's decodable using a JSONDecoder instance.



有关 Codable 的更多信息,请参阅此官方示例.

A type that can convert itself into and out of an external representation.



如果它们匹配,则 JSONDecoder()将工作解码数据。

ContentView.swift:
struct ContentView: View {
    @EnvironmentObject var movieViewModel: MovieListViewModel

    var body: some View {
        MovieList(movie: self.movieViewModel.movie)
    }
}

MovieListViewModel.swift:
public class MovieListViewModel: ObservableObject {
    public let objectWillChange = PassthroughSubject<MovieListViewModel, Never>()
    private var movieResults: [Movie] = []

    var movie: MovieResults = [Movie]() {
        didSet {
            objectWillChange.send(self)
        }
    }

    func load(url: String = "https://api.themoviedb.org/3/discover/movie?sort_by=popularity.desc&api_key=<HIDDEN>") {
        guard let url = URL(string: url) else { return }
        URLSession.shared.dataTask(with: url) { (data, response, error) in
            do {
                guard let data = data else { return }
                let response = try JSONDecoder().decode(MovieResponse.self, from: data)

                DispatchQueue.main.async {
                    for movie in response.results {
                        self.movieResults.append(movie)
                    }

                    self.movie = self.movieResults

                    print("Finished loading Movies")
                }
            } catch {
                print("Failed to decode: ", error)
            }
        }.resume()
    }
}

MovieResponse.swift:
struct MovieResponse: Codable {
    var page: Int
    var total_results: Int
    var total_pages: Int
    var results: [Movie]
}

public class Movie: Codable, Identifiable {
    public var popularity: Float
    public var vote_count: Int
    public var video: Bool
    public var poster_path: String
    public var id: Int
    public var adult: Bool
    public var backdrop_path: String
    public var original_language: String
    public var original_title: String
    public var genre_ids: [Int]
    public var title: String
    public var vote_average: Float
    public var overview: String
    public var release_date: String

    enum CodingKeys: String, CodingKey {
        case popularity = "popularity"
        case vote_count = "vote_count"
        case video = "video"
        case poster_path = "poster_path"
        case id = "id"
        case adult = "adult"
        case backdrop_path = "backdrop_path"
        case original_language = "original_language"
        case original_title = "original_title"
        case genre_ids = "genre_ids"
        case title = "title"
        case vote_average = "vote_average"
        case overview = "overview"
        case release_date = "release_date"
    }

    public init(popularity: Float, vote_count: Int, video: Bool, poster_path: String, id: Int, adult: Bool, backdrop_path: String, original_language: String, original_title: String, genre_ids: [Int], title: String, vote_average: Float, overview: String, release_date: String) {
        self.popularity = popularity
        self.vote_count = vote_count
        self.video = video
        self.poster_path = poster_path
        self.id = id
        self.adult = adult
        self.backdrop_path = backdrop_path
        self.original_language = original_language
        self.original_title = original_title
        self.genre_ids = genre_ids
        self.title = title
        self.vote_average = vote_average
        self.overview = overview
        self.release_date = release_date
    }

    public init() {
        self.popularity = 0.0
        self.vote_count = 0
        self.video = false
        self.poster_path = ""
        self.id = 0
        self.adult = false
        self.backdrop_path = ""
        self.original_language = ""
        self.original_title = ""
        self.genre_ids = []
        self.title = ""
        self.vote_average = 0.0
        self.overview = ""
        self.release_date = ""
    }
}

public typealias MovieResults = [Movie]

MovieCellViewModel.swift:
public class MovieCellViewModel {
    private var movie: Movie

    public init(movie: Movie) {
        self.movie = movie
    }

    public func getTitle() -> String {
        return self.movie.title
    }

    // add more properties or functions here
}

MovieCell.swift:
struct MovieCell: View {
    var movieCellViewModel: MovieCellViewModel

    var body: some View {
        Text(self.movieCellViewModel.getTitle())
    }
}

MovieList.swift:
struct MovieList: View {
    @EnvironmentObject var movieViewModel: MovieListViewModel

    var movie: MovieResults

    var body: some View {
        List(self.movie) { movie in
            MovieCell(movieCellViewModel: MovieCellViewModel(movie: movie))
        }
    }
}

关于JSON 解码器 无法读取数据,因为它的格式不正确,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59315038/

相关文章:

javascript - 如何在html中使用javascript重复解析json数据

c++ - 如何将结构属性转换为 C++ 中的指针引用?

sql-server - ColdFusion 10 serializeJSON 将是/否字符串转换为 bool 值 - 如何阻止它?

ios - SwiftUI 查看所有 View ,包括工作 TableView

ios - swiftUI中scrollView的填充高度

c++ - 如何使用 json 解析器的 boost property_tree 创建空数组节点

javascript - 使用 JQuery 和 Javascript 获取 json 并解析它的最简单方法?

ios - 如何在 SwiftUI 和 iOS 14 中更改单元格背景颜色?

swiftui - swiftUI 中的动画渐变填充

swiftui - 如何以编程方式更改 swiftUI DatePicker 的选定值