0

I am working on an iOS app.

There is a viewController A that perfoms a segue programmatically to a detail viewController D.

On that detail viewController D the user may change some information that should be updated when clicking the back button to viewController A.

On viewController A I have included this function:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    determineMyCurrentLocation()
    print("reloading data")

        downloadJSONFavoritos {
            print("reloading viewwillappear")
        
        self.collectionViewFavoritos.reloadData()
    }
}

My issue is that this function is not always called when back to viewController A, and then the information in A is not updated as it should.

mvasco
  • 4,965
  • 7
  • 59
  • 120
  • You can have `closure` which will be pass and called, when user perform action on `viewController D` and this `closure` will trigger your updating logic – vpoltave Jun 30 '20 at 19:54
  • @vpoltave, please let me know what is that closure you are telling me – mvasco Jun 30 '20 at 19:56
  • You are misunderstanding the viewController life-cycle. `ViewWillAppear` is called when ‘A’ is created and shown. ‘A’ is not destroyed when you go to ‘D’ so that method is not called again. This is not the way to pass data back to a viewController. – Magnas Jun 30 '20 at 19:56
  • @Magnas, would you mind telling me the proper way to trigger the updating logic when back to A? – mvasco Jun 30 '20 at 19:59
  • 1
    This post is excellent - https://stackoverflow.com/questions/5210535/passing-data-between-view-controllers?rq=1 – Magnas Jun 30 '20 at 20:00
  • 3
    If view controller presents view controller D as a full-screen modal or pushes it onto a navigation stack then when view controller D is closed then view controller A's `viewWillAppear(_:)` should be called. That said, that's is not a good way to pass information back. You should use the delegate design pattern, or pass a closure to view Controller D that it would invoke when the new data is available. Blindly triggering a download of JSON in viewWillAppear is not a good approach. – Duncan C Jun 30 '20 at 20:01

1 Answers1

2

I will create simple example, please adaptate it to your needs.

ViewController A:

class ViewControllerA: UIViewController {

    func someMethod() {
        let viewControllerD = // creation and displaying logic of your viewController D
        viewControllerD.updateCompletionHandler = { [unowned self] in 
            /// Any updates goes here ...
        }
    }
}

ViewController D:

class ViewControllerD: UIViewController {

   var updateCompletionHandler: (() -> Void)?

   /// Just example
   @IBAction func triggerUpdateButton(_ sender: UIButton) {
       /// Call it, in place where user make changes
       updateCompletionHandler?()   
   }
}

If you have any questions, let me know in the comments.

vpoltave
  • 1,612
  • 3
  • 14
  • 31
  • Thanks, but I don't know where to include the piece of code that should go in A. – mvasco Jun 30 '20 at 20:11
  • @mvasco _There is a viewController A that perfoms a segue programmatically_ - here. If after this you still have problems, please add code, where you are creating `ViewController D` to your question. – vpoltave Jun 30 '20 at 20:15
  • This is how viewController D is called: performSegue(withIdentifier: "mis_dispositivos_a_detalle", sender: nil) – mvasco Jun 30 '20 at 20:17
  • @mvasco Then you need to change this to something like this: https://stackoverflow.com/a/53267661/6057764, shouldn't causes any problem. – vpoltave Jun 30 '20 at 20:21
  • I don't get the solution for my issue in your proposed link – mvasco Jul 01 '20 at 17:16
  • @mvasco You need to have property (closure) inside your `ViewControllerD`, and you need to assign this property inside `ViewControllerA`, to do this, you need a `ViewControllerD` instance inside `ViewControllerA`, in your current implementation, you don't have instance, because you use `performSegue`. – vpoltave Jul 02 '20 at 15:49