Pergunta

Synopsis

Because of the way I am not getting my app to pass data as I intend, I am lead to ask the following questions:

  • In general, how can I pass data from a Navigation Controller to its imbedded View Controller?
  • Specifically, does the prepareForSegue method in a Navigation Controller ever get called? If so, how?

The Setup

I have the following:

  • A View titled User View Controller,
    linked to a custom class JRMUserViewController (which extends UIViewController).
    This view is imbedded in:
  • A Navigation View titled Navigation To User View,
    linked to a custom class JRMNavigationToUserViewController (which extends UINavigationController).

    IMPORTANT NOTE:
    To start with, I did not have User View Controller imbedded in the Navigation Controller. The Navigation Controller and its linked class did not exist.

  • A Table View titled Issue Table View Controller,
    linked to a custom class JRMIssuesTableViewController (which extends UITableViewController).
  • A Button linked to a Modal Segue that goes to the Navigaton To User View.
    The Segue is identified by the text "IssuesToUserView".

StoryBoard Setup

Intended Functionality

The idea is that when I am on the Issue Table View Controller, I can click on the button and it will take me to the User View Controller, where I will see the current user's avatar, and a label with the current user's full name.

To accomplish this (before I embeded the User View Controller in the Navigation Controller), I passed data from the JRMIssuesTableViewController to the JRMUserViewController in the former's prepareForSegue method:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    NSLog(@"\nSEGUE IDENTIFIER:\n%@", [segue identifier]);
    if([[segue identifier] isEqualToString:@"IssuesToUserView"]) {
        JRMUserViewController *vc = [segue destinationViewController];
        vc.currentUser = self.currentUser;
        NSURL *url = [[NSURL alloc] initWithString:[vc.currentUser.avatarUrls objectForKey:@"48x48"]];
        NSLog(@"\nURL:\n%@", url);
        NSData *data = [NSData dataWithContentsOfURL:url];
        [vc.view addSubview:vc.avatar];
        [vc.avatar setImage:[[UIImage alloc] initWithData:data]];
        vc.userLabel.text = vc.currentUser.displayName;    
   }
}

And it worked. Clicking the button on the first view took me to the second view, where the current user's information was displayed:

Issue Table View

User View -- Working

Unexpected Behavior

After this, out of necessity, I had to embed User View Controller in the Navigation Controller that I mentioned earlier. Now of course, after doing this, I had uncaught exceptions at runtime because, in my overridden prepareForSegue, I was sending messages to the Navigation Controller instead of to the User View Controller. To fix this, I extended UINavigationController, naming it JRMNavigationToUserViewController, and linked the Navigation View to it, as I mentioned in the setup.

Then, figuring that a UINavigationController would call its own prepareForSegue before going to its embedded View, I overrode the prepareForSegue method in JRMNavigationToUserViewController:

- (id)passValuesToDesitinationOfSegue:(UIStoryboardSegue *)segue {
    NSLog(@"Calling [JRMNavigationToUserViewController passValuesToDestinationOfSegue]");
    JRMUserViewController *destination = [segue destinationViewController];
    destination.server = self.server;
    destination.currentUser = self.currentUser;
    destination.avatar = self.avatar;
    [destination.view addSubview:destination.avatar];
    destination.userLabel = self.userLabel;
    return destination;
}

#pragma mark - Navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    NSLog(@"Calling [JRMNavigationToUserViewController prepareForSegue]");
    [self passValuesToDesitinationOfSegue:segue];
}

This time, when I clicked on the button, the User View Controller did not receive the data. It looked like this:

User View -- Not Working

Apparently, the prepareForSegue method in JRMNavigationToUserViewController was never called, as it would have logged the message:

Calling [JRMNavigationToUserViewController prepareForSegue]
Calling [JRMNavigationToUserViewController passValuesToDestinationOfSegue]

I could not find these lines printed anywhere in the console.

Summary

Here again are my questions:

  • In general, how can I pass data from a Navigation Controller to its imbedded View Controller?
  • Specifically, does the prepareForSegue method in a Navigation Controller ever get called? If so, how?
Foi útil?

Solução

You're misusing UINavigationController here. Take a look at your storyboard: you've got a table controller that somehow presents a navigation controller, which in turn has a user controller as its root controller. I think what you want is to have the navigation controller contain the table controller, and have taps on the table trigger a push segue to the user view controller. So, the nav controller should be on the left with the table controller in the middle and the user controller on the right.

Then, the -prepareForSegue:sender: method in the table controller would be written such that it looks at the selected cell and sets the corresponding attributes of the user controller (which is the segue's destination).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top