prepareForSegue vs. pushViewController

I've noticed somthing interesting when using segues and I do not know why it happens. If someone could explain that would be great.


I am using a Storyboard for the first time and hooked up a number of segues. I named the segues and used the prepareForSegue method. What I am trying to do is the following.


The HomeViewController in my navigation stack conforms to a delegate. When this degelate method is called it checks to see if the next view FeedViewController in the navigation stack has been loaded. If it has, then is reloads the tableView (feedsTableView) on this view. Here is the delegate call back method.


func floDataHanlderDidFinishLoading(dataHandler : FLODataHandler) -> ()
    {
        if(self.feedViewController!.feedsTableView != nil)
        {
            println("The reloads feedsTableView is called")
            self.feedViewController!.feedsTableView.reloadData()
        }
    }


When I am using the prepareForSegue method, the if (self.feedViewController!.feedsTableView != nil) is never satisfied even if FeedViewController has been loaded. However if I use a presentViewController method that's called when a button is pressed, if (self.feedViewController!.feedsTableView != nil) is satisfied and feedsTableView gets reloaded.


Here is my prepareForSegue method.


override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
    {
        if segue.identifier == "FeedViewSegue"
        {
            println("Segue == FeedViewSegue")
            if let feedVC = self.storyboard!.instantiateViewControllerWithIdentifier("FeedViewController") as? FeedViewController
            {
                println("If let called")
                self.feedViewController = feedVC
            }
        }
    }


Here is the method called when I press a button.


@IBAction func buttonTest(sender: AnyObject)
    {
        /
        let feedVC = self.storyboard!.instantiateViewControllerWithIdentifier("FeedViewController") as! FeedViewController
        self.feedViewController = feedVC
      
        self.navigationController!.pushViewController(self.feedViewController!, animated: true)
    }



Is there some fundamental difference between prepareForSegue and presentViewController that does not allow a view to be instantiated? Why would if (self.feedViewController!.feedsTableView != nil) not be satisfied when using prepareForSegue when in that method I have the same code that used in the method with the button press?


Take care,


Jon

I suspect the problem is not with self.feedViewController (if your segue works, then that is probably set properly). It's more likely with the table view. You should never manipulate another view controller's views directly. You have no idea where it is in its life cycle (e.g. whether or not the view has been loaded yet). You should define a property or method on the destination VC that says "here is the data to be displayed". It should then be up to the destination VC to either 1) just stash the data for later if the view has not been loaded or the VC is not visible or something, or 2) update its view if it's visible (e.g. by storing the data in its model and calling reloadData on a table view).

In any case when investigating issues like this you should break up long chains (if self.someProperty!.someOtherProperty!.someMethod() == "blah") into multiple lines of code, and step through it in the debugger line by line to find out exactly what is nil or not and inspect the values and state of all objects you care about.

Thanks for the input. I will try my luck at the debugger.


Take care,


Jon

When you mention the line below, do you mean the following.


"You should define a property or method on the destination VC that says "here is the data to be displayed"."


When the delegate call back method is called, I am currently writing the line of code below.


self.feedViewController!.feedsTableView.reloadData()


Since this is reloading a tableView in another VC you mentioned this was not ideal. Instead, would the following logic make more sense.


In the home VC I would instead write.


self.feedViewController!.updateTableView()


Then in the FeedVC where the tableView resides I would perform the following in the updateTableView() method.


func updateTableView()
    {
        self.feedsTableView!.reloadData()
    }


I hope this is clear.


Take care,


Jon

It's closer, but it should be called "dataHasChanged" or something similar, not "reloadTableView". The fact that it's currently displayed in a table view should be an implementation detail known only to the detail VC. The message you send should have a higher level meaning. Picture the case where you decide to display it in a collection view, a page view controller or some other UI widget. Your source VC shouldn't have to care.


Anyway I apologize that I seem to have missed the real problem with your prepareForSegue. You shouldn't instantiate the VC from the storyboard. That is already done for you by UIKit when the segue is performed. You just access the destination view controller of the segue via the segue.destinationViewController property. So it would be something along the lines of "let feedVC = segue.destinationViewController as FeedViewController". Maybe some ? in there... I don't do Swift yet. 🙂

Hi Jon, I knows this has been a very long time.

But it seems like I finally found one person with a similar problem online.


Did you figure out what is going wrong?

I dont think there is anything wrong with the tableView, and it gotta be the issue with PerformSegue vs instantiateViewController

Please help me out if you could recall anything.


Thanks,

Yoho

prepareForSegue vs. pushViewController
 
 
Q