0

iOS - How can I pass information between two view Controllers linked through a Manual Segue?

I have two View Controllers each assigned to their respective Views in the Storyboard. I Control-Click Drag from on to the other and select a "manual" "push" segue.

From what I understand I can execute this segue form anywhere in the code by giving it an identifier and using:

performSegueWithIdentifier:@"identifierA" sender:self

What would be the best way to send information about something that was selected to the newly created View Controller?

unom
  • 11,438
  • 4
  • 34
  • 54
  • 1
    Please don't use NSUserDefaults. See http://stackoverflow.com/questions/8458256/performseguewithidentifier-and-shareddata, http://stackoverflow.com/questions/11577484/passing-variables-between-view-controllers, http://stackoverflow.com/questions/7864371/ios-how-to-pass-prepareforsegue-an-object, etc. –  Aug 16 '14 at 13:49
  • I don't know what NSUserDefaults is, but from the looks of it I benefit from my not knowing. Seems the answer below and your link all point in the same direction segue.destinationViewController returns a pointer to the future controller the segue points to in the Storyboard. I will use that. Thanks. – unom Aug 16 '14 at 13:57

2 Answers2

0

Whenever you perform a segue, this method - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender notifies the controller that a segue is about to be performed.

So from this method you get to know about the destination view controller and you can set any property/ pass value to any property of destination view controller.

Something like this.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.

    if([segue.identifier isEqualToString:@"yourIdentifier"] ){
        YOUR_Destination_Controller *vc = (YOUR_Destination_Controller *)  segue.destinationViewController;
        vc.someProperty = YES;   //in example someProperty is a BOOL 
     }
      else {
        //Do whatever accordingly

     }


}

Hope this helps

Sarim Sidd
  • 2,166
  • 2
  • 22
  • 31
  • Ok so the "future" controller is already created when prepareForSegue is called and I access a pointer to it in segue.destinationViewController? – unom Aug 16 '14 at 13:54
0

I am slightly confused about your question.

Let's assume you have VC1 that opens VC2.

If you want to pass information from root controller(vc1) to new one(vc2)

With segues best you can do is create public property in VC2 and set it before method executes. You can attach just before method executes in prepareForSegue method. So implementation will be something like this:

//
//  VC1.m
//  StackOverflow

#import "VC1.h"
#import "VC2.h"

@implementation VC1



-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if( [segue.identifier isEqualToString:@"yourSegueId"] )
    {
        if( [segue.destinationViewController isKindOfClass:[VC2 class]] )
        {
            [(VC2*)segue.destinationViewController setMyPassedString:@"YOUR STRING FROM VC1"];
        }
    }
}

@end

//
//  VC2.h
//  StackOverflow

#import <UIKit/UIKit.h>

@interface VC2 : UIViewController

@property(nonatomic, strong) NSString* myPassedString;

@end

I personally don't like this approach as you are creating public properties on VC2, which may not be needed at all. However this is a limitation on how storyboard works, and only way to avoid this is to use good old fashioned xib's and designated initializers where you can put your params.

If you want to pass information from new controller(vc2) back to root(vc1)

Here you could basically use two approaches: by passing weak reference to vc2, store it, and then use it when needed to update something on vc1. This is called delegate pattern, however it could be used in much much more powerful and encapsulated way called BLOCKS.

Here is simple implementation with blocks:

//
//  VC2.h
//  StackOverflow

#import <UIKit/UIKit.h>

@interface VC2 : UIViewController

@property(nonatomic, copy) void(^vc1UpdateBlock)(NSString* string);

@end


//
//  VC2.m
//  StackOverflow

#import "VC2.h"

@implementation VC2

-(void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    _vc1UpdateBlock(@"PUT YOUR PASSED STRING HERE");
}

@end

//
//  VC1.m
//  StackOverflow

#import "VC1.h"
#import "VC2.h"

@implementation VC1



 -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if( [segue.identifier isEqualToString:@"yourSegueId"] )
    {
        if( [segue.destinationViewController isKindOfClass:[VC2 class]] )
        {
            [(VC2*)segue.destinationViewController setVc1UpdateBlock:^(NSString * stringFromVC2) {

                NSLog(@"I'm printing in VC1 string %@, passed from VC2", stringFromVC2);

            }];
        }
    }
}

@end

Again if you use xib files directly you can use designated initializers and hide block property, however with storyboards you must create your block publicly available.

hris.to
  • 6,235
  • 3
  • 46
  • 55