Как сделать вызовы GET API с большим ответом JSON в Swift 5? - PullRequest
2 голосов
/ 13 июля 2020

Я пытаюсь получить данные Covid 19 по всем странам и их штатам по болезни . sh.

Ранее я получал данные json из разных API, используя этот метод. Ответ в тех случаях был короче по сравнению с этим.

Я разместил следующие коды:

//  Webservice.swift

import Foundation

class Webservice {
    
    let countriesURL: String = "https://disease.sh/v3/covid-19/jhucsse"
    
    func getAllCountries(completion: @escaping ([Country]?) ->()) {
        
        guard let url = URL(string: countriesURL) else {
            
            completion(nil)
            return
        }
        
        let request = URLRequest(url: url)
        
        URLSession.shared.dataTask(with: request) { data, response, error in
            
            guard let data = data, error == nil else {
                
                print("No data in response: \(error?.localizedDescription ?? "Unknown error").")
                
                DispatchQueue.main.async {
                    completion(nil)
                }
                return
            }
            
            let countries = try? JSONDecoder().decode([Country].self, from: data)
            DispatchQueue.main.async {
                countries == nil ? completion(nil) : completion(countries)
            }
        }.resume()
        
    }
    
}

Поскольку я использовал дизайн MVVM, вот моя модель, ViewModel и View.

//  Model
//  Country.swift

import Foundation

struct Country: Decodable {
    
    var country: String
    var updatedAt: String
    var stats: Stats
    var coordinates: Coordinates
    var province: String
}

struct Stats: Decodable {
    
    var confirmed: Int
    var deaths: Int
    var recovered: Int
}

struct Coordinates: Decodable {
    
    var latitude: String
    var longitude: String
}
//  ViewModel
//  CountryListViewModel.swift

import Foundation

class CountryListViewModel: ObservableObject {
    
    @Published var countries = [CountryViewModel]()
    
    init() {
        fetchCountries()
    }
    
    func fetchCountries() {
        Webservice().getAllCountries() { countries in
            if let countries = countries {
                self.countries = countries.map(CountryViewModel.init)
            }
        }
    }
    
}


class CountryViewModel {
    
    var country: Country
    
    init(country: Country) {
        
        self.country = country
    }
    
    let id = UUID()
    
    var name: String {
        return self.country.country
    }
    
    var updatedAt: String {
        return self.country.updatedAt
    }
    
    var stats: Stats {
        return self.country.stats
    }
    
    var coordinates: Coordinates {
        return self.country.coordinates
    }
    
    var province: String {
        return self.country.province
    }
    
}
//  View
//  ContentView.swift


import SwiftUI

struct ContentView: View {
    
    @ObservedObject private var  countryListVM = CountryListViewModel()
    
    
    var body: some View {
        List( self.countryListVM.countries, id:\.id) { country in
            Text(country.name)
        }
    }
}

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

Моя проблема в том, что когда я вызываю Webservice.getAllCountries (), он возвращает ноль. Может ли кто-нибудь взглянуть на код и сказать, что не так? Спасибо!

PS: Я создал макет json с меньшим количеством объектов (20-30) и вызвал Webservice.getAllCountries (), в этом случае он вернул и сопоставил значения. Он не работает с большим ответом JSON. Помогите !!

1 Ответ

1 голос
/ 13 июля 2020

Вам следует избегать использования try ?, за исключением ситуаций, когда вы действительно не заботитесь о сбоях. do/try/catch - лучший подход, поскольку он сообщит вам почему что-то не удалось.

Изменение вашего кода на

do {
    let countries = try JSONDecoder().decode([Country].self, from: data)
    DispatchQueue.main.async {
        completion(countries)
    }
} catch {
    print(error)
    completion(nil)
}

дает нам ошибку на консоли -

Swift.DecodingError.Context (codingPath: [_JSONKey (stringValue: «Индекс 509», intValue: 509), CodingKeys (stringValue: «Province», intValue: nil)], debugDescription: «Ожидаемая строка value, но вместо этого найдено null. ", lowerError: nil))

, что имеет смысл, поскольку не во всех странах есть провинции. Чтобы исправить это, сделайте province необязательным в вашей модели данных

struct Country: Decodable {
    
    var country: String
    var updatedAt: String
    var stats: Stats
    var coordinates: Coordinates
    var province: String?
}
...