Dave Chambers
Dave Chambers

Reputation: 2563

How can I pass an NSString from one View Controller to another?

I made a very simple storyboard based project with two View Controllers.

I want to simply access a string declared in VC1 from VC2. The second VC should then display the text in a textfield upon the press of a button.

I do not want to use delegation, a separate class for global data or global variables and Extern. Instead, I read that it was easy to achieve variable sharing using a reference to one VC in the other.

For my code shown below, XCode didn't complain, however my problem is this: The NSLog in the second VC returns null.

If anybody can tell me how to amend the code to pass the string to the second VC/ tell me where I'm going wrong I would appreciate it.

VC1 Header:

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

@property NSString* textToPassToOtherVC;

VC1 Implementation:

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController
@synthesize textToPassToOtherVC = _textToPassToOtherVC;

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

    _textToPassToOtherVC = @"Here is some text";
    NSLog (@"Text in VC1 is: %@", _textToPassToOtherVC);
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return YES;
}

@end

VC2 Header:

#import <UIKit/UIKit.h>

@class ViewController;

@interface ViewController2 : UIViewController

@property (nonatomic, strong) ViewController *received;

@property (strong, nonatomic) IBOutlet UITextField *textDisplay;

- (IBAction)textButton:(id)sender;

@end

VC2 Implementation:

#import "ViewController2.h"
#import "ViewController.h"

@interface ViewController2 ()

@end

@implementation ViewController2
@synthesize textDisplay;
@synthesize received;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

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

}

- (void)viewDidUnload
{
    [self setTextDisplay:nil];
    [super viewDidUnload];
    // Release any retained subviews of the main view.
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return YES;
}

- (IBAction)textButton:(id)sender {

    NSLog (@"Text in VC1 from VC2 is: %@", self.received.textToPassToOtherVC);

    textDisplay.text = self.received.textToPassToOtherVC;
}
@end

Upvotes: 2

Views: 4410

Answers (4)

jrturton
jrturton

Reputation: 119242

Your second view controller needs to have its received property set to a value that represents the first view controller.

With storyboard-based projects, this is typically done in prepareForSegue:. This method will be called in your first view controller before the segue to your second view controller is performed.

(In my opinion you would be better off passing just the string to your second view controller rather than a pointer to the whole view controller as this reduces dependency and is the only information your second view controller really needs, but let's not complicate things.)

Here are the steps I think you need to get this working:

  • Give the segue from your first view controller to your second a name in the storyboard. For this example, I'll call it mySegue.
  • Import "ViewController2.h" in "ViewController.m" - your first view controller will need to know that the second view controller has a received property.
  • Add a prepareForSegue: method like so in your first view controller:

    - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
    {
        if ([segue.identifier isEqualToString:@"mySegue"])
        {
            ViewController2 *targetVC = (ViewController2*)segue.destinationViewController;
            targetVC.received = self;
        }
    }
    

Hopefully it's pretty clear what this code is doing.

Upvotes: 3

Peter Warbo
Peter Warbo

Reputation: 11700

Have you checked that your self.received is not null/nil?

Set a breakpoint in the code to see if self.received is actually initialized (if it's not, then that's why you don't see anything):

- (IBAction)textButton:(id)sender {

    // Breakpoint here
    NSLog (@"Text in VC1 from VC2 is: %@", self.received.textToPassToOtherVC);

    textDisplay.text = self.received.textToPassToOtherVC;
}

Upvotes: 0

sridvijay
sridvijay

Reputation: 1526

Try using an NSNotification. When you need to send the string, post a NSNotification with the object!

Put when you want to send the string (after you give the string a value of course):

    yourString = @"Hello";

    [[NSNotificationCenter defaultCenter] postNotificationName:@"sendString" object:yourString];

and in your second View Controller:

-(void)viewDidLoad:
{
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(ThingYouWantToDoWithString:) name:@"sendString" object:nil];
}

- (void)ThingYouWantToDoWithString:(NSNotification *)notification{
        // Make sure you have an string set up in your header file or just do NSString *theString = [notification object] if your using ARC, if not allocate and initialize it and then do what I just said
        theString = [notification object];
        NSLog("%@", theString);
        [self performSelector:@selector(OtherThings:) object:theString];
}

Hope this helps!

Upvotes: 0

mamackenzie
mamackenzie

Reputation: 1166

Your mistake is based on a fundamental misunderstanding of properties. Properties are merely syntactic sugar for dealing with the boilerplate and implementation details of getters and setters. Although setting _textToPassToOtherVC will indeed make the property return that value, it does not "inform" the other, because it's reference to "received" is set to nil by default, and never set by you.

If anywhere before you actually check the value of this shared text, you have the lines:

ViewController *myVC1; 
ViewController2 *myVC2;

// ...some initialization.

myVC2.received = myVC1;
// Now the IBAction will display the correct text.

Everything will work.

Upvotes: 1

Related Questions