Search code examples
swiftuinavigationcontrollerjsondecoder

How to overcome delay in navigation to other viewcontroller iOS swift?


I have recently stopped using Alamofire for making HTTP Networking calls as now in swift 4 Apple have introduced Codable-protocol which is very powerful and fast compared to Alamofire. Everything works fine as expected even my response in faster than before. But there is one problem. Before using Codable protocol for parsing data my navigation to other views used to be very fast. But now there is a slight delay in my navigation particularly when navigating to the pages where I am using JSONDecoder to get response. For ex: I have VC1 and VC2, VC1 is a static page where in VC2 I am using JSONDecoder and getting some data and displaying it in collectionView. Now I click on a button in VC1, It just stops for a second before going to VC2. I don't know why this is happening.

Code in VC1:

@IBAction func gotoProductCollectionView(_ sender: UIButton) {

    let viewController = self.storyboard?.instantiateViewController(withIdentifier: "productCollection") as! ProductCollectionViewController
    self.navigationController?.pushViewController(viewController, animated: true)
}

Code in VC2:

class ProductCollectionViewController: UIViewController,UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout {

@IBOutlet weak var productsTableView: UITableView! 

var productsData = [ProductData]()

override func viewDidLoad() {
    super.viewDidLoad()
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    getProductData()
}

func getProductData() {
    self.productsData = []
    guard let productDataURL = URL(string: "MyURL") else {return}
   DispatchQueue.global(qos: .background).async {
     do {
         let data = try Data(contentsOf: productDataURL)
         self.productsData = try 
 JSONDecoder().decode([ProductData].self, from: data)
         print(self.productsData)
         print(self.productsData.count)
         for productNames in self.productsData {
             print(productNames.product_name!)
         }
        }catch let error {
           print(error)
       }
      DispatchQueue.main.async {                
            self.productsTableView.reloadData()
        }
     }
   } 
} 

Product Model Object:

struct ProductData: Codable {

var product_id: String?
var product_name: String?
var product_price: String?
var product_special_price: String?
var product_sale_of: String?
var product_brand: String?
var product_image: String?

private enum CodingKeys: String, CodingKey {
    case product_id
    case product_name
    case product_price
    case product_special_price
    case product_sale_of
    case product_brand
    case product_image
}

init(product_id: String? = nil, product_name: String? = nil, product_price: String? = nil, product_special_price: String? = nil, product_sale_of: String? = nil, product_brand: String? = nil, product_image: String? = nil) {

    self.product_id = product_id
    self.product_name = product_name
    self.product_price = product_price
    self.product_special_price = product_special_price
    self.product_sale_of = product_sale_of
    self.product_brand = product_brand
    self.product_image = product_image
}

init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    product_id = try container.decode(String.self, forKey: .product_id)
    product_name = try container.decode(String.self, forKey: .product_name)
    product_price = try container.decode(String.self, forKey: .product_price)
    product_special_price = try container.decode(String.self, forKey: .product_special_price)
    product_brand = try container.decode(String.self, forKey: .product_brand)
    product_image = try container.decode(String.self, forKey: .product_image)
    if let value = try? container.decode(Int.self, forKey: .product_sale_of) {
        product_sale_of = String(value)
    } else {
        product_sale_of = try container.decode(String.self, forKey: .product_sale_of)
    }
  }
}

Solution

  • The answer is in this line

    let data = try Data(contentsOf: productDataURL)
    

    Obviously you download the data from internet in the DispatchQueue.main

    You need to do it in separate background queue and then update the view from the main again. Don't forget to use .async calls.