Passing values and messages between views on iPhone

I am working on an iPhone application with some regular views and a table view, and I need to have the table view communicate with the main view. Seemingly a simple enough problem, but as I searched and searched, I could not find any concrete examples of how to do this, just a bunch of vague references about how views need to talk to each other and a larger number of folks suggesting the use of singletons.

Now, I have been known to use a global variable or two in my day, but in this instance, I figured I would dig a bit deeper.

As it turns out, the means to accomplish this for my task was easier than I thought. All that I did was to store a reference to the primary view controller in my secondary view controller, and that gave me access to any of the member variables in that class. In addition, this also gives me the ability to send messages to methods in that class.

So, in my primary view controller header file, we have the following:

#import <UIKit/UIKit.h>
 
@interface PassingValuesBetweenViewsViewController : UIViewController {
	IBOutlet UILabel *label;
	int selectedValue;
}
 
@property (nonatomic, retain) UILabel *label;
@property (nonatomic) int selectedValue;
 
- (IBAction)buttonWasTapped;
 
- (void)tableItemWasSelected:(int)itemSelected;
 
@end

And in the primary view controller implementation file:

#import "PassingValuesBetweenViewsViewController.h"
#import "SecondaryViewController.h"
 
@implementation PassingValuesBetweenViewsViewController
 
@synthesize label;
@synthesize selectedValue;
 
- (void)didReceiveMemoryWarning {
	// Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
 
	// Release any cached data, images, etc that aren't in use.
}
 
- (void)viewDidUnload {
	// Release any retained subviews of the main view.
	// e.g. self.myOutlet = nil;
}
 
- (void)dealloc {
    [super dealloc];
}
 
- (IBAction)buttonWasTapped
{
	SecondaryViewController *svc = [SecondaryViewController alloc];
	svc.vc = self;
	[self.view addSubview:svc.view];
}
 
- (void)tableItemWasSelected:(int)itemSelected
{
	NSLog(@"tableItemWasSelected called with %d", itemSelected);
	NSLog(@"The current value of selectedValue is %d", selectedValue);
	label.text = [NSString stringWithFormat: @"You selected #%d", itemSelected];
}
 
@end

The selectedValue member is an integer that gets updated in the table view with the selected cell, and the tableItemWasSelected methods is called from the table view when a cell is selected. In the buttonWasTapped method, the secondary view controller gets a reference to the primary view controller after it is allocated, and this enables the magic to happen.

Here is the secondary view controller header file:

#import <UIKit/UIKit.h>
 
#import "PassingValuesBetweenViewsViewController.h"
 
@interface SecondaryViewController : UITableViewController {
	PassingValuesBetweenViewsViewController *vc;
}
 
@property (nonatomic, retain) PassingValuesBetweenViewsViewController *vc;
 
@end

And the secondary view controller implementation file:

#import "SecondaryViewController.h"
 
@implementation SecondaryViewController
 
@synthesize vc;
 
- (void)didReceiveMemoryWarning {
	// Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
 
	// Release any cached data, images, etc that aren't in use.
}
 
- (void)viewDidUnload {
	// Release any retained subviews of the main view.
	// e.g. self.myOutlet = nil;
}
 
#pragma mark Table view methods
 
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}
 
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 50;
}
 
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
 
    static NSString *CellIdentifier = @"Cell";
 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    }
 
    // Set up the cell...
	cell.textLabel.text = [NSString stringWithFormat: @"Cell #%d", indexPath.row];
    return cell;
}
 
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
	vc.selectedValue = indexPath.row;
	[vc tableItemWasSelected:indexPath.row];
	[self.view removeFromSuperview];
}
 
- (void)dealloc {
    [super dealloc];
}
 
@end

As you can see here, the primary view controller is references from the didSelectRowAtIndexPath method, both in setting a member variable through standard dot notation, and in sending a message with a parameter to the primary view controller.

I have posted a copy of this code if you would like to download the entire project and work with it:

PassingValuesBetweenViews.zip

Please keep in mind this is not finished or production quality code.

7 Comments

  1. Tom says:

    Does this not create Cyclical Dependencies … because each file is importing one another??

    Thats the error i am getting when i try to do this!

  2. BP says:

    Tom: You just have to make sure to get the includes into the right files. When it talks about the implementation files above, that is the .m files, and the headers are the .h files. I posted the whole solution in the zip file link above, have you tried that? I just built it and ran it in the simulator just fine in Xcode version 3.2.1 (1613). BP

  3. […] as you need a way to pass values back and forth from one view to another. I think I might have a blog post from a few months ago to talk about this […]

  4. BP says:

    Tom: I was starting to notice some oddities when doing this kind of message passing in my latest application, which I would guess is exactly what was happening to you when you tried it. I found that, in my secondary view controller, instead of doing the #include for the header of the primary view controller, I just used the @class directive for the primary view controller. That cleaned up the errors I was getting due to the headers being cyclical. BP

  5. xcoder says:

    link was broken, can you update link? other hand, thank you for posting

  6. BP says:

    Sorry about that, I forgot to switch this link over when I did a redesign on one of my other web sites. The link should work just fine for you now. BP

  7. […] // do something here » Blog Archive » Passing values and messages between views on iPhone So, in my primary view controller header file, we have the following: #import @interface PassingValuesBetweenViewsViewController : UIViewController { IBOutlet UILabel * label; int selectedValue; } @property ( nonatomic, retain ) UILabel * label; @property ( nonatomic ) int selectedValue; – ( IBAction ) buttonWasTapped; – ( void ) tableItemWasSelected : ( int ) itemSelected; @end As it turns out, the means to accomplish this for my task was easier than I thought. All that I did was to store a reference to the primary view controller in my secondary view controller, and that gave me access to any of the member variables in that class. In addition, this also gives me the ability to send messages to methods in that class. And in the primary view controller implementation file: […]

Leave a Reply