BFree
BFree

Reputation: 103750

Passing data from one view controller to another; iOS <=4 vs iOS 5

First, a little background. I'm new to iOS development, I've been in .Net land for a long time, and that's probably why I'm even asking this question, but here goes.

The basic setup is this. You have a UINavigationController with a RootViewController we'll call MasterViewController. When some action happens on this MasterViewController, we want to drill into a DetailsViewController. However, we also want to pass some data to the DetailsViewController.

It is my understanding, that in previous versions of the SDK (prior to iOS 5) the approach was similiar to this:

@implementation MasterViewController

    -(IBAction)someAction
    {
       DetailsViewController *dvc = [[DetailsViewController alloc]initWithNibName:@"DetailsView" bundle:nil];
       dvc.someDataProp = [self getSomeDataSomeHow];
       [[self navigationController] pushViewController:dvc animated:YES];
    }

@end

Now however, in iOS 5, it seems that this is now done using the Storyboard and segues. In XCode you set up the segue from the MasterViewController to the DetailsViewController, and then in code you do something like this:

-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
   [segue.destinationViewController setSomeDataProp:[self getSomeDataSomeHow]];
}

My question is basically this: The older approach somehow feels a lot cleaner to me. You're being very explicit about the type of ViewController you're pushing on to the navigation stack and you can set properties easily on it. In the new approach though, destinationViewController is of type id (for obvious reasons), and it just feels a lot less clean to me. Again, this could be my .Net side coming out, but is this common in iOS? Just use id and throw caution to the wind?

Upvotes: 7

Views: 7486

Answers (3)

Yvo
Yvo

Reputation: 19263

I haven't been working with iOS that long, but I've seen a few examples where you don't have to cast because of objective-c's loose coupled messaging system.

Instead of checking the segue identifier or casting to a specific ViewController you can do this:

-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
   if ([segue.destinationViewController respondsToSelector: @selector(setCompany:)]) {
      [segue.destinationViewController performSelector: @selector(setCompany:) withObject: self.company];
   }
}

In the first line I ask if the destinationViewController has a method setCompany (if you have a property named company this one would be generated for you). If it does, you can call that method/set that property with the second line of code.

So in this case you don't really have to know the destination ViewController and could easily replace it with a different one that supports handling Companies.

Upvotes: 1

Shiprack
Shiprack

Reputation: 1105

In many cases, the destination view controller for a segue may be a UINavigationViewController, and in that case, the solution (a slight modification of Dennis Mathews' solution above) will need to use the message"topViewController":

if ([segue.identifier isEqualToString:@"My First Segue Identifier"])
{    
   NavitationViewController* navController = [segue destinationViewController];   
   DetailsViewController *dvc = (DetailsViewController*) [navController topViewController]
   // Set the DVC's properties 
}

Upvotes: 4

Dennis Mathews
Dennis Mathews

Reputation: 6975

With Storyboards you can assign a named identifier to the segue, Select the segue and in the Attribute inspector you can add a name to the segue Identifier.

And in the prepareForSegue method you should check for this Identifier and thus you will explicitly know which segue is about to be performed and what the destinationViewController will be.

if ([segue.identifier isEqualToString:@"My First Segue Identifier"])
{    
   DetailsViewController *dvc = (DetailsViewController *) segue.destinationViewController;
   // Set the DVC's properties 
}

Upvotes: 6

Related Questions