Swift -解码JSON时出错“期望解码Array< Any>,但却找到了字典,”[重复]

gywdnpxw  于 2023-05-27  发布在  Swift
关注(0)|答案(1)|浏览(119)

此问题已在此处有答案

JSON decoder The data couldn’t be read because it isn’t in the correct format(3个答案)
昨天关门了。
这是我第一次在这里问一个问题,所以请原谅我😁。我使用SwiftUI,我试图从API中获取数据并将其存储在数组中,我现在有2个文件:
MoviesFetcher.swift:

import Foundation

struct Movie: Codable {
    let original_title: String
    let releaseDate: String

}

var movieArray: [Movie] = []

class Fetcher {
    func fetchData(completion: @escaping () -> Void) {
        let urlString = "https://api.themoviedb.org/3/movie/550"
        
        guard let url = URL(string: urlString) else {
            completion()
            return
        }
        
        let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
            if let error = error {
                print("Error: \(error.localizedDescription)")
                completion()
                return
            }
            
            guard let data = data else {
                completion()
                return
            }
            
            do {
                let decoder = JSONDecoder()
                movieArray = try decoder.decode([Movie].self, from: data)
                completion()
            } catch {
                print("Error decoding JSON: \(error)")
                completion()
            }
        }
        
        task.resume()
    }
}

ContentView.swift:

import SwiftUI

struct ContentView: View {
    @State private var movies: [Movie] = []
    
    var body: some View {
        VStack {
            if movies.isEmpty {
                Text("Loading...")
            } else {
                List(movies, id: \.original_title) { movie in
                    Text(movie.original_title)
                }
            }
        }
        .onAppear {
            Fetcher().fetchData {
                movies = movieArray
            }
        }
    }
}
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

鉴于此,MoviesFetcher是我尝试从“www.example.com”获取数据https://api.themoviedb.org/3/movie/550?api_key=d2ea758c1787f6f8715df6713125a180并将其存储在movieArray[]中的代码。
Contentview只是访问movieArray[]并尝试只显示每个电影的标题。
错误:我得到这2个错误在调试控制台

解码JSON时出错:typeMismatch(Swift.Array,Swift.DecodingError.Context(codingPath:[],debugDescription:“预期解码数组,但找到的却是字典。",underlyingError:无))
解码JSON时出错:无法读取数据,因为格式不正确。

这也是我与swift合作的第一年,所以如果有人有更好的方法来做到这一点,我将非常高兴并愿意接受建议。
我没有尝试太多,因为我不知道还有什么其他的方法。

mspsb9vt

mspsb9vt1#

问题是您使用的API只返回一个电影,代码中不包含API键。
这是一个更原生的SwiftUI解决方案,使用async/await和视图模型。
使用lowerCamelCase名称和不同状态的枚举声明结构。添加id成员以免费获得Identifiable的一致性。

struct Movie: Decodable, Identifiable {
    let id: Int
    let originalTitle: String
    let releaseDate: String
}

enum LoadingState {
    case idle, loading, loaded([Movie]), failed(Error)
}

视图模型添加API键并根据当前阶段设置状态。它运行在主线程上,所以你不必关心调度线程。

@MainActor
class Fetcher : ObservableObject {
    
    let apiKey = "••••••••••"
    
    @Published var state: LoadingState = .idle
    
    func fetchData() async  {
        state = .loading
        do {
            let url = URL(string:"https://api.themoviedb.org/3/movie/550?api_key=\(apiKey)")!
            let (data, _) = try await URLSession.shared.data(from: url)
            
            let decoder = JSONDecoder()
            decoder.keyDecodingStrategy = .convertFromSnakeCase // necessary to convert the names
            let movie = try decoder.decode(Movie.self, from: data)
            state = .loaded([movie])
        } catch {
            state = .failed(error)
            print(error)
        }
    }
}

在视图中创建视图模型的示例并在.task中加载数据

struct ContentView: View {
    
    @StateObject private var fetcher = Fetcher()
    
    var body: some View {
        
        VStack {
            switch fetcher.state {
                case .idle: EmptyView()
                case .loading: ProgressView()
                case .loaded(let movies):
                    List(movies) { movie in
                        HStack {
                            Text(movie.originalTitle)
                            Text(movie.releaseDate)
                        }
                    }
                case .failed(let error):
                    Text(error.localizedDescription)
            }
        }
        .task {
            await fetcher.fetchData()
        }
    }
}

相关问题