Deezer API 解码失败?

huangapple go评论71阅读模式
英文:

Deezer API failing to decode?

问题

我理解了,你想要将上述代码翻译成中文。以下是翻译好的部分:

我正在尝试从Deezer的API(网址:https://api.deezer.com/genre)中获取“流派类别”数据,用于我的SwiftUI项目,然而在解码并将数据值分配给我的数组的代码行中,却没有发生这种情况。相反,程序跳转到了我的else条件中。我在其他API(苹果的iTunes API和其他公共测试API)上使用了完全相同的程序结构,它们都可以完全正常工作。是Deezer API 或者我的请求本身出了问题吗?

我的 GenreModel 代码:

struct Genre: Codable {
    let id: Int
    let name: String
    let picture: String
}

我的 GenreViewModel 代码:

final class GenreViewModel: ObservableObject {
    
    @Published var genres: [Genre] = []
    @Published var hasError = false
    @Published var error: UserError?
    
    func fetchGenres() {
        // ... (后续部分)
    }
    
    // ... (后续部分)
    
    enum UserError: LocalizedError {
        case custom(error: Error)
        case failedToDecode
        
        var errorDescription: String? {
            switch self {
                // ... (后续部分)
            }
        }
    }
}

我的 GenreView 代码:

struct GenreView: View {
    let genre: Genre
    var body: some View {
        VStack(alignment: .leading) {
            Text("**Genre**: \(genre.id)")
            Text("**Name**: \(genre.name)")
            Text("**Picture**: \(genre.picture)")
        }
    }
}

我的 ContentView 代码:

struct ContentView: View {
    
    @StateObject private var gVM = GenreViewModel()
    
    var body: some View {
        // ... (后续部分)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

如果你有任何其他需要,请继续提出。

英文:

I'm trying to access "Genre Categories" data from Deezer's API (url: https://api.deezer.com/genre) in my SwiftUI Project, however in the line where I decode and assign the data value to my array, it doesn't happen. Instead the program falls to my else condition. I've used this exact program structure on other API's ( Apple's iTunes API and other public test APIs) and it works with no problem whatsoever. Could there be a problem in Deezer API or my request itself?

My GenreModel Code:
'''

import Foundation

struct Genre: Codable {
    let id: Int
    let name: String
    let picture: String
   
    
}

'''

My GenreViewModel Code:

'''

import Foundation

final class GenreViewModel: ObservableObject{
    
    @Published var genres: [Genre] = []
    @Published var hasError = false
    @Published var error: UserError?
    
    
    func fetchGenres(){
        hasError = false
        let genreUrl = "https://api.deezer.com/genre"
        
        if let url = URL(string: genreUrl){
            
            URLSession.shared.dataTask(with: url){ [weak self] data,response, error in
                
                DispatchQueue.main.async {
                    
                    if let error = error{
                        self?.hasError = true
                        self?.error = UserError.custom(error: error)
                    }
                    
                    else{
                        
                        let decoder = JSONDecoder()
                        //decoder.keyDecodingStrategy = .useDefaultKeys
                        
                        if let data = data,
                            let genres = try? decoder.decode([Genre].self, from: data){
                            
                            self?.genres = genres
                        }
                        
                        else{
                            self?.hasError = true
                            self?.error = UserError.failedToDecode
                        }
                    }
                }
            }.resume()
        }
    }
}


extension GenreViewModel{
    
    enum UserError: LocalizedError{
        case custom(error: Error)
        case failedToDecode
        
        var errorDescription: String?{
            switch self{
            case .failedToDecode:
                return "Failed to decode"
            case .custom(let error):
                return error.localizedDescription
            }
            
            
            
        }
    }
}

'''

My GenreView Code
'''

import SwiftUI

struct GenreView: View{
    let genre: Genre
    var body: some View{
        VStack(alignment: .leading){
            Text("**Genre**: \(genre.id)")
            Text("**Name**: \(genre.name)")
            Text("**Picture**: \(genre.picture)")
        }
    }
        
        
}


struct GenreView_Previews: PreviewProvider{
    
    static var previews: some View{
        GenreView(genre: .init(id: 0, name: "a", picture: "pic"))
    }
}

'''

My ContentView Code

'''

import SwiftUI

struct ContentView: View {
    
    @StateObject private var gVM = GenreViewModel()
    
    var body: some View {
        NavigationView{
            ZStack{
                List{
                    ForEach(gVM.genres, id: \.id){ genre in
                        GenreView(genre: genre).listStyle(.plain)
                    }
                }.listStyle(.plain).navigationTitle("Users")
                    .alert(isPresented: $gVM.hasError, error: gVM.error){
                        Button(action: gVM.fetchGenres){
                            Text("try again")
                        }
                    }
            }.onAppear(perform: gVM.fetchGenres)
        }
        
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

'''

答案1

得分: 1

尝试以下示例代码,其中根 ApiResponse 用于解码从服务器获取的 JSON 数据。

struct ApiResponse: Codable {
    let data: [Genre]
}

struct Genre: Identifiable, Codable {
    let id: Int
    let name, picture, type: String
    let pictureSmall, pictureMedium, pictureBig, pictureXl: String

    enum CodingKeys: String, CodingKey {
        case id, name, picture, type
        case pictureSmall = "picture_small"
        case pictureMedium = "picture_medium"
        case pictureBig = "picture_big"
        case pictureXl = "picture_xl"
    }
}

final class GenreViewModel: ObservableObject {
    @Published var genres: [Genre] = []
    @Published var hasError = false
    @Published var error: UserError?
    
    func fetchGenres() {
        hasError = false
        let genreUrl = "https://api.deezer.com/genre"
        
        if let url = URL(string: genreUrl) {
            URLSession.shared.dataTask(with: url) { data, response, error in
                DispatchQueue.main.async {
                    if let error = error {
                        self.hasError = true
                        self.error = UserError.custom(error: error)
                    } else {
                        if let data = data {
                            do {
                                let decoder = JSONDecoder()
                                let genres = try decoder.decode(ApiResponse.self, from: data)
                                self.genres = genres.data
                                return
                            } catch {
                                print(error)
                            }
                        }
                        self.hasError = true
                        self.error = UserError.failedToDecode
                    }
                }
            }.resume()
        }
    }
}
英文:

Try this example code, where the root ApiResponse is used to decode the json data you get from the server.

struct ApiResponse: Codable {
    let data: [Genre]
}

struct Genre: Identifiable, Codable {
    let id: Int
    let name, picture, type: String
    let pictureSmall, pictureMedium, pictureBig, pictureXl: String

    enum CodingKeys: String, CodingKey {
        case id, name, picture, type
        case pictureSmall = "picture_small"
        case pictureMedium = "picture_medium"
        case pictureBig = "picture_big"
        case pictureXl = "picture_xl"
    }
}

final class GenreViewModel: ObservableObject {
    @Published var genres: [Genre] = []
    @Published var hasError = false
    @Published var error: UserError?
    
    func fetchGenres() {
        hasError = false
        let genreUrl = "https://api.deezer.com/genre"
        
        if let url = URL(string: genreUrl) {
            URLSession.shared.dataTask(with: url){ data,response, error in
                DispatchQueue.main.async {
                    if let error = error {
                        self.hasError = true
                        self.error = UserError.custom(error: error)
                    } else {
                        if let data = data {
                            do {
                                let decoder = JSONDecoder()
                                let genres = try decoder.decode(ApiResponse.self, from: data)
                                self.genres = genres.data
                                return
                            } catch {
                                print(error)
                            }
                        } 
                            self.hasError = true
                            self.error = UserError.failedToDecode
                    }
                }
            }.resume()
        }
    }
}

huangapple
  • 本文由 发表于 2023年5月10日 18:16:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/76217232.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定