Juri
Juri

Reputation: 93

How to update tableView data with delegate protocol?

I am creating my app without a storyboard. I passing data between my 2 controllers using Delegate protocol

protocol CatalogueDelegate {
    func transferProduct(product: JSONProduct?)
}

class CatalogueController: UITableViewController{

var catalogueDelegate: CatalogueDelegate!

override func viewDidLoad() {
    super.viewDidLoad()

    feetchLabelProducts(labelId: 2, qnt: nil) 
}

private func feetchLabelProducts(labelId: Int, qnt: Int?) {
    getLabelProducts(labelId: labelId, qnt: qnt, completed: {
        self.tableView.reloadData()
    })
}

private func getLabelProducts(labelId: Int, qnt: Int?, completed: @escaping () -> ()) {
    APIService.shared.downloadLabelProducts(labelId: labelId, qnt: qnt) { (products, error) in
        if let products = products {
            self.productList = products
        }

        DispatchQueue.main.async {
            completed()
        }
    }
}

override func numberOfSections(in tableView: UITableView) -> Int {
    return 1
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return productList.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: cellProductId, for: indexPath) as! ProductCell
        cell.product = self.productList[indexPath.row]
        return cell
    }
}

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let product = self.productList[indexPath.row]
    catalogueDelegate.transferProduct(product: product)
    let productDetailVC = ProductDetailController()
    navigationController?.pushViewController(productDetailVC, animated: true)
}    
}

I do get data on my ProductDetailController and func transferProduct can print it but I need to update my tableView with this new data but for some reasons self.tableView.reloadData() is not working for me.

import UIKit

class ProductDetailController: UIViewController, UITableViewDelegate, UITableViewDataSource {

let productDetailCell = "productDetailCellId"
var product: JSONProduct?

let tableView: UITableView = {
    let tableView = UITableView()
    return tableView
}()

override func viewDidLoad() {
    super.viewDidLoad()

    tableView.register(ProductDetailCell.self, forCellReuseIdentifier: productDetailCell)
    tableView.delegate = self
    tableView.dataSource = self
    tableView.separatorColor = UIColor.clear

    view.addSubview(tableView)

    view.backgroundColor = UIColor.white

    _ = tableView.anchor(view.topAnchor, left: view.leftAnchor, bottom: buyButton.topAnchor, right: view.rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 0)
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 1
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: productDetailCell, for: indexPath) as! ProductDetailCell

    if let product = self.product {
        print(product.title)
    } else {
        print("No data!!!")
    }

    return cell
}

}

extension ProductDetailController: CatalogueDelegate {
func transferProduct(product: JSONProduct?) {
    guard let item = product else { return }
    self.product = item
    self.tableView.reloadData()
}
}

Can you please help me to solve this problem? I can print received data

extension ProductDetailController: CatalogueDelegate {
func transferProduct(product: JSONProduct?) {
    guard let item = product else { return }
    // I can print new data
    print(item)
    // But I can not update my tablveView with thith new data
    self.product = item
    tableView.reloadData()
}
}

I did set up delegate in AppDelegate file like this

        let productDetailController = ProductDetailController()

    let catalogueController = CatalogueController()
    catalogueController.catalogueDelegate = productDetailController

Upvotes: 1

Views: 1030

Answers (1)

Milan Nosáľ
Milan Nosáľ

Reputation: 19737

You forgot to set the data in the cellForRowAt to the cell:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: productDetailCell, for: indexPath) as! ProductDetailCell

    if let product = self.product {
        // you have to set that product to the cell
        print(product.title)
    } else {
        print("No data!!!")
    }

    return cell
}

EDIT

Rewrite didSelectRowAt in CatalogueController to the following:

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let product = self.productList[indexPath.row]
    let productDetailVC = ProductDetailController()
    productDetailVC.transferProduct(product: product)
    navigationController?.pushViewController(productDetailVC, animated: true)
} 

I am not sure where you set the delegate before, but you are presenting a new productDetailVC that is not the delegate on which you have called transferProduct(). If this is your whole setup, you don't need a delegate pattern, all you need is to do this:

let productDetailVC = ProductDetailController()
productDetailVC.transferProduct(product: product)
navigationController?.pushViewController(productDetailVC, animated: true)

EDIT 2

Reason why that happens is simple. You set the delegate in the AppDelegate:

let productDetailController = ProductDetailController()
let catalogueController = CatalogueController() 
catalogueController.catalogueDelegate = productDetailController

But then here you present another different view controller:

let product = self.productList[indexPath.row]
// this sets a product to the delegate object
catalogueDelegate.transferProduct(product: product)
// but the following two lines present another new view controller,
// not the one that is the delegate!
let productDetailVC = ProductDetailController()
navigationController?.pushViewController(productDetailVC, animated: true)

Upvotes: 1

Related Questions