How to complete function between TableView selection and segue to next ViewController?

39 views Asked by At

My app has the following flow:

  1. View Controller 1 presents TableView with Titles
  2. User selects TableView row
  3. View Controller 1 instructs Model to load the full data for that selected TableView row
  4. Model passes data back to View Controller 1
  5. View Controller 1 passes that data View Controller 2 as part of a segue

This is how I'm passing data to the View Controller 2:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        
        guard let destination = segue.destination as? UINavigationController else {
            return
        }
        
        guard let finalDestination = destination.viewControllers.first as? SegmentedControlViewController else {
            return
        }
        
        if let indexPath = tableView.indexPathForSelectedRow {
            
            let documentId = documentIdArray[indexPath.row]
            finalDestination.documentId = documentId
            print(documentID) // documentId is not nil and is passed to the next view controller successfully
            
            model.getRecipeSelected(docId: documentId) // the output of this is entireRecipe
            finalDestination.entireRecipe = entireRecipe
            print(entireRecipe) // entireRecipe is nil
        }
    }

The app crashes because View Controller 2 is trying to work off of data that isn't there yet. How can I make sure model.getRecipeSelected(docId: documentId) gets the data and passes it to View Controller 2 before I segue to it?

Note: I've confirmed that model.getRecipeSelected(docId: documentId) works by putting it in my viewDidLoad(). The issue seems to be that it hasn't retrieved/passed the data before the segue to View Controller 2.

Edit: I've also tried the following but with no success.

1. Added a completion handler to my model and do everything in prepare function.

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        
        if segue.identifier == "MealPlanToSegmentedControl" {
            
            guard let destination = segue.destination as? UINavigationController else {
                return
            }

            guard let finalDestination = destination.viewControllers.first as? SegmentedControlViewController else {
                return
            }
            
            if let indexPath = tableView.indexPathForSelectedRow {
                
                let documentID = recipeDocIdArray[indexPath.row]
                finalDestination.passedDocID = documentID
                
                model.getRecipeSelected(docId: documentID) {
                    print("(entireRecipe)") // FIXME: SEGUE HAPPENS BEFORE entireRecipe IS ASSIGNED ANY DATA
                    finalDestination.entireRecipe = entireRecipe
                }
            }
        }
    }

2. Added a completion handler to my model and use didSelectRowAt

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        
        let documentID = recipeDocIdArray[indexPath.row]
        
        model.getRecipeSelected(docId: documentID) {
            self.performSegue(withIdentifier: "MealPlanToSegmentedControl", sender: Any?.self)
        }
    }
1

There are 1 answers

2
Harshvardhan Arora On
  1. Add a property in your VC1 that will store your recipe
  2. Create a delegate for your VC1 didReceiveRecipe(recipe:) which will update the recipe property and set your model as the delegate for VC1. After updating the recipe, also call performSegue now and when you reach the point of prepare(for:sender:) gets called, you will definitely have your recipe available.
  3. In your didSelectRow delegate method, ask your model to fetch the recipe which on doing so will call the delegate method.