0

What I want to achieve? I have 2 UITableViewController : AddCardVC and ListDeckController. I want to pass selected Deck in ListDeckController to AddCardVC then updateUI on AddCardVC

My code: (I'm building on Swift 5, iOS 13)

ListDeckController.swift:

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

    let storyboard = UIStoryboard(name: "Main", bundle: nil)

    if let addCardVC = storyboard.instantiateViewController(withIdentifier: "AddCard") as? AddCardVC {
        if let deck = allDecks?[indexPath.row] {
            addCardVC.selectedDeck = deck
        }
    }
    self.navigationController?.popViewController(animated: true)
}

AddCardVC.swift:

var selectedDeck: Deck?
    {
        didSet {
            viewWillAppear(true)
        }
    }

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

        if let deck = selectedDeck {
            //Update UI
            self.chooseDeckButton.setTitle(deck.name, for: .normal)
            print(chooseDeckButton.titleLabel?.text ?? "")

            self.tableView.reloadData()
        }
    }

What happend?

After I got selected Deck in AddCardVC, the console print out chooseDeckButton.titleLabel?.text = "My Deck" which is what I want. But The button title on UI is "Choose your deck" Console image Button on UI

So, why the setButtonTitle not showing on UI in my case?

Thank you for your time

Hiren Dhamecha
  • 658
  • 5
  • 15
  • That is not how you send data back to view controller. Use delegates – Keshu R. Jan 02 '20 at 05:05
  • your chooseDeckButton is in TableCell ? – Anand Prakash Jan 02 '20 at 05:07
  • https://stackoverflow.com/questions/30618172/how-to-send-data-back-by-popviewcontrolleranimated-for-swift – Keshu R. Jan 02 '20 at 05:07
  • @iOSArchitect.com, Yes that's right way to pass data using delegate, but here passing data is not the issue but the button title assignment – Anand Prakash Jan 02 '20 at 05:10
  • 2
    @AnandPrakash He is creating a new instance of addCardVC. instead of refering to previous one. That will never work. He needs to get the previous controller instead. Thats why i said, use delegates – Keshu R. Jan 02 '20 at 05:14
  • Yes exactly , please use the shared url to follow the delegate pattern: https://stackoverflow.com/questions/30618172/how-to-send-data-back-by-popviewcontrolleranimated-for-swift – Anand Prakash Jan 02 '20 at 05:19
  • @Vinh check my answer – Keshu R. Jan 02 '20 at 05:36
  • @iiOSArchitect.com, I followed your guide but it crash my App. The reason is chooseDeckButton is nil on UI when **didSelectDeck(selectedDeck : Deck)** is called. So I tried to called self.selectedDeck = selectedDeck in **didSelectDeck(selectedDeck : Deck)** then update UI on ViewWillAppear like my previous code but the button title on UI still not change – Vinh Phan Tan Jan 02 '20 at 10:17
  • @Anand Prakash, yes, my chooseDeckButton is in a cell of a Static Table View – Vinh Phan Tan Jan 02 '20 at 10:18

1 Answers1

2

First, create a protocol for DeckDelegate

protocol SelectedDeckDelegate {
    func didSelectDeck(selectedDeck : Deck)
}

Now in your ListDeckController.swift, implement the delegate

var deckDelegate : SelectedDeckDelegate?

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
{ 
if let deck = allDecks?[indexPath.row] {
    deckDelegate?.didSelectDeck(selectedDeck: deck)
    self.navigationController?.popViewController(animated: true)
} else {
    print("deck is empty")
}  
}

And in your AddCardVC, when navigating to ListDeckController, assign the delegate to self

// Make AddCardVC conform to SelectedDeckDelegate

class AddCardVC : UIViewController, SelectedDeckDelegate {


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

        if let deck = selectedDeck {
            //Update UI
            self.chooseDeckButton.setTitle(deck.name, for: .normal)
            print(chooseDeckButton.titleLabel?.text ?? "")

            self.tableView.reloadData()
        }
    }

    // assign the delegate to self here

    @IBAction func selectDeckBtnAction(_ sender : Any) {
        let vc = storyboard.instantiateViewController(withIdentifier: "ListDeckController") as? ListDeckController
        vc.deckDelegate = self
        self.navigationController?.pushViewController(vc, animated: true)
    }

    // this will get called whenever selectedDeck is updated from ListDeckController
    func didSelectDeck(selectedDeck: Deck) {
        self.selectedDeck = selectedDeck
        chooseDeckButton.setTitle(selectedDeck.name , for: .normal)
    }
 }
Shabbir
  • 289
  • 2
  • 6
Keshu R.
  • 5,045
  • 1
  • 18
  • 38
  • Thanks for your response. I followed your guide but my app crashed. When **func didSelectDeck(selectedDeck: Deck)** is called, the **chooseDeckButton** is nil. So I tried to called **self.selectedDeck = selectedDeck** in **didSelectDeck(selectedDeck : Deck)** then update UI on **ViewWillAppear** like my previous code but the button title on UI still not change – Vinh Phan Tan Jan 02 '20 at 10:28
  • chooseDeckBtn is nil ? Are you sure? can you share your complete ListDeckController and AddCArdVC code here – Keshu R. Jan 02 '20 at 10:34
  • 1
    @ iOSArchitect.com, sorry, after i clean up my code, it worked. Your answer is correct. Thank you a lot – Vinh Phan Tan Jan 02 '20 at 10:47