Search code examples
swiftsegue

How do I pass data to 2 or more ViewControllers during segue


I'm trying to pass data from a SwipeCardVC to a CardDetailVC that is the parent to multiple children view controllers embedded in different containers (i.e. ReadReviewVC).

While I can pass the data to the parent CardDetailVC with no problem, the children view controllers also need access to the data I'm passing along.

So far, I've tried casting an additional destination in my prepare for segue code as you can see below:

Update: Storyboard Screenshot

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "toDetailVC" {
        let cardDetailVC = segue.destination as? CardDetailVC
        cardDetailVC?.card = CardController.shared.topCard
        let readReviewVC = segue.destination as? ReadReviewsVC
        readReviewVC?.card = CardController.shared.topCard
    }

// UPDATED CODE - CustomViewController
class CardViewController: UIViewController {
    var card: Card?
}

// UPDATED CODE - ParentViewController
class ParentCardDetailVC: CardViewController {

    private(set) lazy var childrenVCs: [CardViewController] = {
        return [
            UIStoryboard(name: "Detail", bundle: nil).instantiateViewController(withIdentifier: "cardDetailVC"),
            UIStoryboard(name: "Detail", bundle: nil).instantiateViewController(withIdentifier: "readReviewsVC")]
    }() as! [CardViewController]

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(true)
        for child in childrenVCs {
            child.card = self.card
        }
    }
}

// UPDATE ChildVC
class CardDetailVC: CardViewController {

    // MARK: - Properties
    override var card: Card? {
        didSet {
            updateViews()
        }
    }
.
.
.
    // MARK: - Methods
    private func updateViews() {
        guard let card = card else { print("No card object found in \(#function)") ; return }

        cardImageView.image = card.image
        foodNameLabel.text = card.foodName
        priceLabel.text = card.price
        restaurantLabel.text = card.restaurantName
        descriptionLabel.text = card.description
        streetLabel.text = card.street
        cityStateLabel.text = card.cityState
    }
}

While the cardDetailVC.card value is correct, the readReviewVC.card value always comes back nil, leaving me to believe I can only have 1 destination per identifier. Please help refactor this code or let me know if there is a different way to accomplish this task (i.e: NSNotifications or KVO).


Solution

  • Not only can you not segue to 2 UIViewControllers, your parent VC should have the data and then it should be delegated to the children. I say delegated lightly because this is not the same thing as delegate methods in Swift.

    Something like this should happen.

    ParentVC contains an array childrenVCs:[CustomViewController]. So on viewWillAppear() loop through the childrenVCs and provide them data.

    class CustomViewController: UIViewController {
        var card:Int!
    
        //...
    }
    
    class CardDetailVC: CustomViewController {
        //...
    }
    
    class ReadReviewsVC: CustomViewController {
        //...
    }
    
    class ParentVC: CustomViewController {
    
        //Setup Children ViewControllers inside code or inside storyboard
        var childrenViewControllers:[CustomViewController] = [//...]
    
        func viewWillAppear() {
            for children in childrenViewControllers {
                children.card = self.card
            }
        }
    }
    
    class SegueFromController:UIViewController {
        override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            if segue.identifier == "toDetailVC" {
                let cardDetailVC = segue.destination as? ParentVC
                cardDetailVC?.card = CardController.shared.topCard
            }
        }
    }