0

This is a Q&A Style Post

If I want to pass parameters, such as an NSString, NSArray, or NSDictionary, from one view controller to another, what is the easiest way to do this?

Mike
  • 9,765
  • 5
  • 34
  • 59
  • Yes, this question has been asked before, but it is also asked frequently and per the Stack Exchange blog "it is not merely OK to ask and answer your own question, it is explicitly encouraged", which is what I've done here. This was purposefully done, "Q&A Style", in order to provide what I think is a pretty clear and concise answer to a very common question that does have good answers already, but I think mine is in a new and useful format. – Mike Aug 28 '14 at 03:23
  • The easiest way is to simply pass it. VC A passes the parm to VC B when it inits it, or assigns the parm to a property of VC B, or calls a method of VC B, passing the parm. Or VC B can be given a pointer to A as a delegate and can call back to A to get the parm. (I've yet to understand why this is considered such a complicated problem.) – Hot Licks Sep 11 '14 at 15:24
  • @HotLicks Hence my answer below ;) I still see this question often, so I wanted to try to give a more detailed answer than I've seen before. – Mike Sep 11 '14 at 16:43
  • But isn't the (unspoken) question more often "How to I gain addressability to VC B while in VC A if my app is poorly designed or I'm using some sort of framework that obscures that info?" – Hot Licks Sep 11 '14 at 16:49
  • hmmm as someone who is not so far removed from being a 'noobie', I would tend to disagree in general, but I'm sure that is true in many cases. – Mike Sep 11 '14 at 17:17

1 Answers1

0

There are multiple ways to achieve this, but two of the cleanest methods would involve passing the parameter(s) into a custom init method for the next view controller, or setting the parameter(s) as a property of the next view controller.

Note that this is not restricted to passing data between view controllers - view controllers are objects and any objects can use the following principles, I'm simply using view controllers for the following examples.

Both of these examples are using a simple UITableViewController as the initial view controller, and the next view controller will be passed the user's selection from a list of cells where they can choose their favorite color, as well as the current date of their selection. This can be done FROM any type of view controller TO any type of view controller with a few minor modifications, and within reason there's really no limit to the types/quantity of information that can be passed this way.

keep in mind that you likely don't want a massive initializer method with 10 parameter names, so in that case you might want to have individual properties and set each one accordingly. You also might want to keep the initialization/setup code to a single line if there's only a few parameters, so using a custom initializer method might be for you in that case.

Demo table view setup

#import "TestTableViewController.h"
#import "NextViewController.h"

@interface TestTableViewController ()

@end

@implementation TestTableViewController


- (void)viewDidLoad {
    [super viewDidLoad];

    self.colors = @[@"Red", @"Orange", @"Yellow", @"Green"];
}


#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.colors.count;
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ColorCell"];

    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"ColorCell"];
    }
    cell.textLabel.text = self.colors[indexPath.row];

    return cell;
}

Method #1 - Custom Initializer

NextViewController.h

#import <UIKit/UIKit.h>

@interface NextViewController : UIViewController

// expose the custom initializer so other view controller's can pass in the parameters we want to pass
- (instancetype)initWithFavoriteColor:(NSString *)favoriteColor currentDate:(NSDate *)date;

@end

NextViewController.m

#import "NextViewController.h"

@implementation NextViewController

// implement the custom initializer method
- (instancetype)initWithFavoriteColor:(NSString *)favoriteColor currentDate:(NSDate *)date {
    self = [super init];

    // do whatever you want here with the favorite color string and current date that 
    // was passed in, such as save them to instance variables...

    return self;
}

@end

Implement method #1 in our demo table view:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    // get the color they selected for this row from our data source array
    NSString *selectedColor = self.colors[indexPath.row];

    // initialize the next view controller using the handy init method we created
    NextViewController *nextVC = [[NextViewController alloc] initWithFavoriteColor:selectedColor currentDate:[NSDate date]];
    [self.navigationController pushViewController:nextVC animated:YES];
}

Method #2 - Creating/Setting Properties

NextViewController.h

#import <UIKit/UIKit.h>

@interface NextViewController : UIViewController

@property (nonatomic, retain) NSString *favoriteColor;
@property (nonatomic, retain) NSDate *currentDate;

@end

NextViewController.m

#import "NextViewController.h"

@implementation NextViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    // do something here with your properties - by the time the view has loaded
    // they will have been set/passed from the original view controller
    self.favoriteColor...
    self.currentDate...
}

@end

Implement method #2 in our demo table view:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    // get the color they selected for this row from our data source array
    NSString *selectedColor = self.colors[indexPath.row];

    // initialize the next view controller normally, and set its favorite color property
    // to be what the user selected
    NextViewController *nextVC = [NextViewController new];
    nextVC.favoriteColor = selectedColor;
    nextVC.currentDate = [NSDate date];
    [self.navigationController pushViewController:nextVC animated:YES];
}

In both instances, you have now quickly and easily passed multiple pieces of information from one view controller to another.

Mike
  • 9,765
  • 5
  • 34
  • 59
  • Shouldn't you really say "can be done FROM any type of *iOS object* TO any type of *iOS object*? There's absolutely nothing special about view controllers in this regard. – Hot Licks Sep 11 '14 at 16:49
  • Sure, but it would seem to me that *most* new programmers run into this specific issue in particular. I'll add a note. – Mike Sep 11 '14 at 16:52
  • One big problem is that programmers new to Objective-C seem to somehow regard view controllers as different from other objects. – Hot Licks Sep 11 '14 at 16:57