Получение ошибки при попытке декодировать данные в Swift через API бэкэнда.IOS

Программируем под IOS
Ответить
Anonymous
 Получение ошибки при попытке декодировать данные в Swift через API бэкэнда.

Сообщение Anonymous »

Я пытаюсь получить данные через серверный API и получаю данные по функции запроса в сетевом классе, например
if let getData = data{
result = .success(getData)
let respondString = String(data:getData, encoding: .utf8) ?? "could not convert our data into string"
// print("backend response is \(respondString)") //here i'm getting data perfeclty
}

но я не знаю, почему данные не декодируются идеально, когда я вызываю сетевые вызовы в домашнем контроллере для загрузки данных, они не работают нормально. Я приложил все скриншоты как а также код сетевого класса, пожалуйста, помогите решить эту проблему.
NETWORKING CALSS:
struct NetworkService{
static let shared = NetworkService()
private init(){
}

func fetchAllCategories(completion: @escaping(Result)-> Void){
request(route: .fetchAllCategories, method: .get, completion: completion)
}

// 1.private function access in this struct not outsude the struct
private func createRequest(route: Route, method: Method, parameters : [String:Any]? = nil) -> URLRequest?
{
//baseUrl = "https://yummie.glitch.me/temp"
let urlString1 = Route.baseUrl + route.description //calling from route class
guard let url = URL(string: urlString1) else { return nil }//convet url into string
var urlRequest = URLRequest(url: url)
urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
//rawvlaue return cases as a string
urlRequest.httpMethod = method.rawValue

if let params = parameters{

switch method{

case .get:
// https:// google.com/books?type=cartoon&page=1
var urlComponent = URLComponents(string: urlString1)
urlComponent?.queryItems = params.map {
URLQueryItem(name: $0, value: "\($1)")}
urlRequest.url = urlComponent?.url

case .post, .delete, .patch:
let bodyData = try? JSONSerialization.data(withJSONObject: params, options: [])
urlRequest.httpBody = bodyData
}
}
return urlRequest
}

//2. Create One Generic Function to Make Different Types of API Requests
private func request(route: Route,method: Method, parameters: [String: Any]? = nil, completion: @escaping(Result) -> Void){

guard let request = createRequest(route: route, method: method, parameters: parameters) else {//caling 1st function
completion(.failure(AppError.unknownError)) //calling error that define in APPErro class
return

}

URLSession.shared.dataTask(with: request){ (data, response, error) in
var result: Result?

if let getData = data{
result = .success(getData)
let respondString = String(data:getData, encoding: .utf8) ?? "could not convert our data into string"
// print("backend response is \(respondString)") //here i'm getting data perfeclty
}

else if let error = error{
result = .failure(error)
print("error is:\(error.localizedDescription)")
}
DispatchQueue.main.async {
print("success \(result)")
self.handleRequest(result: result , completion: completion)
}
}.resume()

}

//4.hnalde the api response from api response class and show to decoadlbe data that shows on api

private func handleRequest(result:Result?, completion: @escaping(Result) -> Void){
guard let result = result else {
completion(.failure(AppError.unknownError))
return
}

switch result {
case .success(let data):
let decoder = JSONDecoder()
guard let response = try? decoder.decode(ApiResponse.self, from: data) else {
completion(.failure(AppError.errorDecoding))
return
}
if let error = response.error{
completion(.failure(AppError.ServerError(error)))
}

if let decodedData = response.data{
completion(.success(decodedData))

}else{
completion(.failure(AppError.unknownError))
}
case .failure(let error):
completion(.failure(error))
}

}

}

КЛАСС ДОМАШНЕГО КОНТРОЛЛЕРА:
class HomeController: UIViewController {

@IBOutlet weak var tableView: UITableView!
var categories: [String] = ["Food Category","Popular Dishes","Chief Specials"]

var categoresdish: [DishCategory] = []{
didSet{
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
var popular: [Dish] = []{
didSet{
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
var specials: [Dish] = []{
didSet{
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}

override func viewDidLoad() {
super.viewDidLoad()
self.loadData()

self.tableView.delegate = self
self.tableView.dataSource = self
self.tableView.register(UINib(nibName: String(describing: HomeTableViewCell.self), bundle: .main), forCellReuseIdentifier: String(describing: HomeTableViewCell.self))

}
private func loadData(){
ProgressHUD.show()
NetworkService.shared.fetchAllCategories { [weak self] (result) in
switch result{

case .success(let allDishes):
ProgressHUD.dismiss()
self?.categoresdish = allDishes.categories ?? []
self?.popular = allDishes.populars ?? []
self?.specials = allDishes.specials ?? []

case .failure(let error): // when i load the load the data the control goes to here
print("faheem error is \(error.localizedDescription)")
ProgressHUD.showError()
}
}
}


extension HomeController : UITableViewDelegate,UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return categories.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
self.configureDisehsCell(tableView, cellForRowAt: indexPath)
}

func configureDisehsCell(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{

guard let dishesCell = tableView.dequeueReusableCell(withIdentifier: String(describing: HomeTableViewCell.self), for: indexPath) as? HomeTableViewCell else {return UITableViewCell()}
dishesCell.categoreisData = self.categories[indexPath.row]
dishesCell.row = indexPath.row
dishesCell.categoriesDishsLoad = self.categoresdish
dishesCell.popularDishesLoad = self.popular
dishesCell.chiefSpecialsLoad = self.specials

return dishesCell
}

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
// return indexPath.row == 0 ? 140: 240
let row = indexPath.row
switch row {
case 0:
return 140
case 1:
return 260
case 2:
return 200

default:
return 0
}

}

}

enter code here

КЛАСС МАРШРУТА
enum Route{
static let baseUrl = "https://yummie.glitch.me"

case fetchAllCategories

var description: String{
switch self{
case .fetchAllCategories:
return "/dish-categories"
}
}

}

КЛАСС МЕТОДА
enum Method: String{
case get = "GET"
case post = "POST"
case delete = "DELETE"
case patch = "PATCH"
}

КЛАСС ПРИЛОЖЕНИЯ
enum AppError: LocalizedError{
case errorDecoding
case unknownError
case inValidUrl
case ServerError(String)

var errorDescription: String?{
switch self{

case .errorDecoding:
return "response could not be decoded"
case .unknownError:
return "i have no idea what the error is"
case .inValidUrl:
return "give me a valid url"
case .ServerError(let error):
return error
}
}
}

КЛАСС APIRESPONSE
struct ApiResponse: Decodable{
let status: Int //like 100,200,300
let message: String //message from the backend
let data: T? // we get the different types of data like int,string, custom types etc and convert json into particular strucures
let error: String? //errro from backend comes or not

}

ВСЕ КЛАССЫ МОДЕЛЕЙ
struct DishCategory: Decodable{
var id: String
var name: String
var image: String
}

struct Dish: Decodable{
var id:String
var name:String
var image:String
var description:String
var calories:Double

var formatedCalories:String{
return String(format: "%2f" , calories)
}
}

struct Orders{
var id: String
var name: String
var dish: Dish // kis dish pr order howa he
}

struct AllDishes: Decodable{
let categories: [DishCategory]?
let populars: [Dish]?
let specials: [Dish]?
}


Подробнее здесь: https://stackoverflow.com/questions/686 ... ackend-api
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «IOS»