My app has the following flow:
- View Controller 1 presents TableView with Titles
- User selects TableView row
- View Controller 1 instructs Model to load the full data for that selected TableView row
- Model passes data back to View Controller 1
- 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)
}
}
didReceiveRecipe(recipe:)which will update the recipe property and set your model as the delegate for VC1. After updating the recipe, also callperformSeguenow and when you reach the point ofprepare(for:sender:)gets called, you will definitely have your recipe available.didSelectRowdelegate method, ask your model to fetch the recipe which on doing so will call the delegate method.