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)
}
}
}
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.