Reputation: 21
I'm using trying to get the data through backend API and I'm getting the data on requisition function in networking class like
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
}
but I don't know why data is not decoded perfectly when I'm calling the networking calls in home controller to load the data it's not working fine I'm attached all the screenshots as well as networking class code please help to resolve this issue.
NETWORKING CALSS:
struct NetworkService{
static let shared = NetworkService()
private init(){
}
func fetchAllCategories(completion: @escaping(Result<AllDishes,Error>)-> 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<T:Decodable>(route: Route,method: Method, parameters: [String: Any]? = nil, completion: @escaping(Result<T, Error>) -> 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<Data, Error>?
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<T:Decodable>(result:Result<Data, Error>?, completion: @escaping(Result<T, Error>) -> 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<T>.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))
}
}
}
HOME CONTROLLER CLASS:
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
ROUTE CLASS
enum Route{
static let baseUrl = "https://yummie.glitch.me"
case fetchAllCategories
var description: String{
switch self{
case .fetchAllCategories:
return "/dish-categories"
}
}
}
METHOD CLASS
enum Method: String{
case get = "GET"
case post = "POST"
case delete = "DELETE"
case patch = "PATCH"
}
APPERROR CLASS
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 CLASS
struct ApiResponse<T:Decodable>: 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
}
ALL MODEL CLASSES
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]?
}
Upvotes: 0
Views: 669