0

I'm having some trouble understanding why the reloadData() line crashes with the following error 'unexpected found nil while unwrapping optional value'(also, why is it an optional?). Basically, when user taps a button it fires an API request, second VC(recipesVC) is shown and when data is retrieved from the API, in receivedRecipes method (previous VC) I want to reloadData from recipesVC (currentVC) As my data is correctly passed to recipesVC, I don't see why reloadData() won't work on the same VC. Could you please give me a little help with this? thank you.

    override func viewDidLoad() {
    super.viewDidLoad()

    let recipes = Notification.Name(rawValue: "gotRecipes")
    NotificationCenter.default.addObserver(self, selector: #selector(receivedRecipes),name: recipes, object: nil)
}

@objc func receivedRecipes() {
    let recipesVC = storyboard?.instantiateViewController(withIdentifier: "recipesList") as! RecipesViewController
    recipesVC.recipesList = request.recipeDetails
    recipesVC.recipes.reloadData()
}
Julm
  • 25
  • 7
  • Is `recipesVC.recipes` nil? Correctly set/connectected on the part of the VC? You don't present `recipesVC`? How is declared `recipes` in `RecipesViewController`? But if it's correctly set, you'll still have this: https://stackoverflow.com/questions/12523198/storyboard-instantiateviewcontrollerwithidentifier-not-setting-iboutlets – Larme Dec 19 '17 at 08:39
  • recipesVC.recipes is nil, indeed. recipes is correctly set as IBOutlet and connected, i've used a segue to present the VC. when user taps button, segue is performed, VC is showed and then when I get data I want to reload tableview. – Julm Dec 19 '17 at 08:52
  • Then it's surely because of this: https://stackoverflow.com/questions/12523198/storyboard-instantiateviewcontrollerwithidentifier-not-setting-iboutlets The reason are the same. – Larme Dec 19 '17 at 08:52
  • 1
    What? You are saying that you already showed `RecipesViewController` (with a segue), and on the previous ViewController, when it gets data, it need to say to the `RecipesViewController` shown to reload? If that's what you mean, that's clearly not what's doing your code: `recipesVC` is a whole new object, not the one presented. – Larme Dec 19 '17 at 08:57
  • This is exactly what I'm trying to do. – Julm Dec 19 '17 at 09:02
  • Its not good to access IBOutlets of one class from another.It can be nil and i think this can be problem in your case(recipesVC.recipes.reloadData()) – Vikky Dec 19 '17 at 09:04
  • I've tried using let recipesVC = RecipesViewController() instead of using a new object but it still crashes. – Julm Dec 19 '17 at 09:17
  • @Julm please tell me one thing in which view controller you have written above code.And where are you posting gotRecipes Notification. And where are you getting request.recipeDetails. – Rahul Dasgupta Dec 19 '17 at 09:20
  • @Julm this question is very unclear. Please edit your question and again post it. – Rahul Dasgupta Dec 19 '17 at 09:26
  • I've written this code in my first VC, when user taps a button it fires an API request, second VC(recipesVC) is shown and when data is retrieved from the API, in receivedRecipes method (previous VC) I want to reloadData from recipesVC (currentVC). – Julm Dec 19 '17 at 09:27
  • "I've tried using let recipesVC = RecipesViewController() instead of using a new object but it still crashes" That's still creating a whole new object. What you could do is to create a custom delegate for `PreviousViewController` set it to the `RecipesViewController`, and when needed `PreviousViewController` will call a reload method. – Larme Dec 19 '17 at 09:30
  • Ok, I will try to use a custom delegate. I will keep you posted. Thanks. – Julm Dec 19 '17 at 09:33
  • @Julm I have done it using Notification. I have edited my answer. You can check it. – Rahul Dasgupta Dec 19 '17 at 10:13

2 Answers2

0

Add validation to your data:

func receivedRecipes() {
    guard let details = request.recipeDetails else { return }
    let recipesVC = storyboard?.instantiateViewController(withIdentifier: "recipesList") as! RecipesViewController
    recipesVC.recipesList = details
    recipesVC.recipes.reloadData()
}

The next tip, you can update your notification and get recipes from the notification.object, but previously you should paste them into:

let parsedRecipes = Recipes()
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "gotRecipes"), object: parsedRecipes, userInfo: nil) 

Also show recipesVC after it initialization with: self.present(...) or self.navigationController?.show(...)

biloshkurskyi.ss
  • 1,358
  • 3
  • 15
  • 34
  • To be more precise on my problem and as explained by Larme, I'm showing RecipesViewController (with a segue), and on the previous ViewController, when it gets data, it needs to say to the RecipesViewController shown to reload. – Julm Dec 19 '17 at 09:14
  • So, you should save `ViewController` from the `segue` and use it, instead of creating new one `let recipesVC = storyboard?...` – biloshkurskyi.ss Dec 19 '17 at 09:19
0
 @objc func receivedRecipes() {
     NotificationCenter.default.post(name: NSNotification.Name(rawValue: "recipes"), object: nil, userInfo: ["data":request.recipeDetails])

 } 

In your currentVC

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(receivedRecipes(notification:)),name: NSNotification.Name(rawValue: "recipes"), object: nil)
}

 @objc func receivedRecipes(notification: Notification) {
    recipesList = notification.userInfo
    recipes.reloadData()
 }
Rahul Dasgupta
  • 894
  • 6
  • 18
  • this would probably be the best solution however the parameter userInfo must be a dictionary and my request.recipedetails variable is an array of struct. – Julm Dec 19 '17 at 10:41
  • I passed userInfo as dictionary – Rahul Dasgupta Dec 19 '17 at 11:23
  • I've tried your solution and it actually worked perfectly. I've posted a notification from my class where I retrieved the data, added the observer directly in the currentVC and passed it through with userInfo. There was no need to go back into the VC where the button was tapped. I guess notifications/observers are a bit clearer to me now. Thanks for your help! – Julm Dec 19 '17 at 14:50