0

I have some weird issue here as somehow I am unable to pass NSString from one class to another. I deployed the same method that worked on other classes.

I am trying to pass a string from secondViewController to my firstViewController. Here's what I did.

firstViewController.h

NSString *pickUpAddressString;
@property (nonatomic, retain) NSString *pickUpAddressString;

firstViewController.m

@synthesize pickUpAddressString;
-(void) viewWillAppear:(BOOL)animated {
NSLog(@"pickUpAddressString is %@", pickUpAddressString); // why it's null here?
    PickUpAddress.text = pickUpAddressString; // PickUpAddress is a UITextField
}

secondViewController.m

FirstViewController *controller = [[FirstViewController alloc]init];
    controller.pickUpAddressString = selectedAddress; // here, I set the string
    NSLog(@"selected address :%@\npickUpAddressString:%@", selectedAddress, controller.pickUpAddressString); // I had verified that both strings are valid.
    [self.navigationController popViewControllerAnimated:YES]; // pop to firstView
Gavin
  • 2,784
  • 6
  • 41
  • 78
  • 1
    If you are popping back to the firstView controller, it means that it was already initiated. Why do you reinitiated it with FirstViewController *controller = [[FirstViewController alloc]init]; if it is allready on the navigationController stack? – Ladislav Aug 28 '11 at 14:00

1 Answers1

3

You are creating a new instance of FirstViewController...

FirstViewController *controller = [[FirstViewController alloc]init];

...different from the original instance that (I'm assuming) pushed the SecondViewController and to which you are returning via popViewControllerAnimated:.


Basically, what you need is to pass data back to the controller that pushed the SecondViewController, in this case, the FirstViewController.

Perhaps, the easiest way to achieve this is what @Ladislav suggested in his comment:

NSArray *viewControllers = [self.navigationController viewControllers];
FirstViewController *firstVC = [viewControllers objectAtIndex:[viewControllers count] - 2];

However, keep in mind that this introduces a direct dependency between SecondViewController and FirstViewController. Or, in other words, SecondViewController is now tightly coupled to FirstViewController.

In a nutshell, when it comes to pass data back up the hierarchy, it is a best practice to use loose coupling to avoid direct dependencies between your view controllers (tight coupling). The benefits of doing so include code reusability and testability. In order to achieve loose coupling you need to define a generic interface for observers (e.g. delegation, notifications, etc).

It is also worth mentioning the importance of putting state information in model objects. Avoid putting data inside the controllers, unless it's strictly presentation data.

More on this topic: What's the best way to communicate between view controllers?

Community
  • 1
  • 1
albertamg
  • 28,492
  • 6
  • 64
  • 71
  • Oh, I didn't know that. How should I call the instance of my FirstViewController then? I tried `FirstViewController.pickUpAddressString = @"123"` but doesnt work – Gavin Aug 28 '11 at 14:10
  • 1
    Get the array of all view controllers in the navigationController with: NSArray *viewControllers = [self.navigationController viewControllers], then get the the second to last one with FirstViewController *firstVC = (FirstViewController *)[viewControllers objectAtIndex:viewControllers.count - 2]; All this code has to be before the popViewControllerAnimated is called! – Ladislav Aug 28 '11 at 14:14
  • @Ladislav Thanks a lot. It works and I learnt something new today! – Gavin Aug 28 '11 at 14:20
  • @Ladislav Just a question, what does the (FristViewController *) means? Even without it, it still worked. – Gavin Aug 28 '11 at 14:27
  • @MaTaKazer This will work but bear in mind that this kind of direct dependency tightly couples your view controllers making your code less reusable. For communicating back up the hierarchy, consider using **loose coupling** by defining a generic interface for observers (e.g. delegation) – albertamg Aug 28 '11 at 14:31
  • @albertamg Ok, so it's like some sort of reference? – Gavin Aug 28 '11 at 14:33
  • @MaTaKazer Read through http://stackoverflow.com/questions/569940/whats-the-best-way-to-communicate-between-view-controllers – albertamg Aug 28 '11 at 14:38
  • (FirstViewController *) will tell the compiler, that the object it will get will be of class FirstViewController. – Ladislav Aug 28 '11 at 14:45