Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS

How to Pass Values between Multiple View Controllers using Delegate / Protocol

Basically, I am now intend to use delegate to pass values between view controllers.

The flow of the view controllers is A -> B -> C

When the user does some action in the "C" view controller, how to pass the value back to the first view controller, which is "A"?

Below is the code of the First VC and Third VC:

#import "ViewController.h"
#import "ThirdViewController.h"

@interface ViewController ()<PassValueProtocal>
@property (weak, nonatomic) IBOutlet UILabel *myLabel;

@end

@implementation ViewController
{
    ThirdViewController *thirdVC;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}

- (void) passValueBack:(NSString *)value
{
    NSLog(@"HAHAH");
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


- (IBAction)segueToSecondVC:(UIButton *)sender
{
    thirdVC = [ThirdViewController sharedManager];
    thirdVC.delegate = self;
}

@end
#import "ThirdViewController.h"

@interface ThirdViewController ()
@property (weak, nonatomic) IBOutlet UITextField *myTextField;

@end

@implementation ThirdViewController

+ (id) sharedManager
{
    NSLog(@"myDelegate sharedManager");
    static ThirdViewController *sharedManager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{ sharedManager = [[self alloc] init]; });
    return sharedManager;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (IBAction)passValueAction:(UIButton *)sender
{
    NSLog(@"%@", self.delegate);
    if ([self.delegate respondsToSelector:@selector(passValueBack:)])
    {
        [self.delegate passValueBack:self.myTextField.text];
    }
}

The delegate method is never triggerred and "self.delegate" is always "null". I am not sure why.

2 Answers

Hi, you need to create a manual seque in the storyboard and create an instance of your view controller via segue.destinationViewController

#import "FirstViewController.h"
//In the third controller user prepareForSegue:sender: method

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    FirstViewController *firstVC = (FirstViewController *)segue.destinationViewController;
    firstVC.propertyName = dataYouWantToPass;
}

(Old question but...) You're using a Singleton and delegation which are two different ways of communicating between VCs (and I stay away from shared instances because they're bad for testing). I think all you need to do is pass the delegate from A, in the prepareForSegue method to B, and then pass it from B to C in B's prepare for segue method. It looks like you're trying to set the third delegate(C) from the first VC(A) by using the shared instance which is wonky. So do this in A and B

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    NextViewController *nextVC = (NextViewController *)segue.destinationViewController;
    nextVC.delegate = self; // self for First vc, self.delegate for second VC.
} 

Keep passing the delegate that way and use the delegation pattern, where NextViewController will be replaced by which ever type is next, i.e., ThirdVC or SecondVC. Keep away from the singleton.