4

I'm working on an app and I need to pass data between view controllers. I know this is a common question but I couldn't find an answer for my problem : I'm able to pass data from the FirstViewController (MasterViewController in my case) to the SecondViewController (SettingsViewController) but not the reverse. What happens is that I call a method from the FirstViewController in my SecondViewController.m file. This works and it logs the data. But when I quit the SecondViewController (using [[self presentingViewController] dismissViewControllerAnimated:YES completion:nil];) the data is reset. I tried using other methods to pass data but it didn't work. I'm using this code to pass data:

MasterViewController *vc = [[MasterViewController alloc] initWithNibName:@"MasterViewController" bundle:nil];

[vc setPorts:SelectedPorts];

I also tried replacing [vc setPorts:SelectedPorts]; with vc.selectedCellIndexes = SelectedPorts; but the same problem occurs.

the setPorts method is declared in the FirstViewController.h file and SelectedPorts is a variable I declared in SecondViewController.m (it's not nil I checked).

Here's the setPorts: in FirstViewController.m :

- (void) setPorts:(id)selectedPorts {
selectedCellIndexes = selectedPorts;
NSLog(@"selectedCellIndexes : %@", selectedCellIndexes);
}

This logs the good value but when I log it in viewWillAppear in FirstViewController.m it's reset to the value it has before I called the method from SecondViewController.m.

Just to clarify, if I DON'T quit the SecondViewController.m, the data isn't reset.

I did read all your comments, and I really thanks you for your help. for convenience, I used a global variable.

Thanks for your help.

jrock007
  • 105
  • 1
  • 7

6 Answers6

1

In secondViewController, You create protocol

  #import <UIKit/UIKit.h>

@protocol sampleDelegate <NSObject>

- (void)passValue:(id)selectedPorts

@end

@interface SecondViewController : UIViewController

@property (nonatomic, strong) id <sampleDelegate> passDelegate;

@end

In viewDidLoad or wherever method as per your need, call method like this,

[self.passDelegate passValue:selectedPorts];

In FirstViewController.h,

Import the delegate <sampleDelegate>,

#import "SecondViewController.h"

@interface FirstViewController : UIViewController<SampleDelegate>

@end

In FirstViewController.m,

-(void)passValue:(id)selectedPorts
{
    id receivedValues = selectedPorts;
}

and set self in your SecondViewController allocation,

SecondViewController *vc = [[SecondViewController alloc] initWithNibName:@"SecondViewController" bundle:nil];
vc.passDelegate = self;
karthika
  • 4,085
  • 3
  • 21
  • 23
  • allocate it in FirstViewController.m ? I need to pass data from SecondViewController not to SecondViewController – jrock007 Oct 21 '13 at 09:54
  • btw I forgot to mention I'm using a storyboard – jrock007 Oct 21 '13 at 09:55
  • Are you need to reverse? secondview to Master view? – karthika Oct 21 '13 at 09:55
  • Yes, I need to pass the data back... FROM SecondViewController TO MasterViewController – jrock007 Oct 21 '13 at 09:56
  • you need to create delegate and pass data through delegate method – karthika Oct 21 '13 at 09:58
  • I tried that a couple of times, but could you give me some code just in case I did it wrong? – jrock007 Oct 21 '13 at 09:59
  • the passValue method isn't called, maybe because I didn't import the delegate in FirstViewController.h well... How am I supposed to do that? – jrock007 Oct 21 '13 at 10:09
  • import the delegate in your firstViewController and one more important when you create secondviewController, after the allocation put delegate = self. i have edited code. please look. – karthika Oct 21 '13 at 10:12
  • I tried using #import and #import "sampleDelegate" but none of them worked (I have errors) – jrock007 Oct 21 '13 at 10:17
  • You have to import like this, @interface FirstViewController : UIViewController – karthika Oct 21 '13 at 10:22
  • I added that (I get @interface MasterViewController : UITableViewController ) and I have an error : "cannot find protocol declaration for 'sampleDelegate'. I imported SecondViewController (#import "SettingsViewController.h") and I added that in SettingsViewController.h : a protocol sampleDelegate - (void)passValue:(id)selectedPorts; a end – jrock007 Oct 21 '13 at 10:38
  • ok good. now that method is fired or not? or receiving any error? – karthika Oct 21 '13 at 10:43
  • I have an error : cannot find protocol declaration for 'sampleDelegate' when I try to import it – jrock007 Oct 21 '13 at 10:46
  • Where you declare the protocol declaration? @protocol sampleDelegate – karthika Oct 21 '13 at 10:48
  • Declare proctol in SecondViewController, above the interface declaration – karthika Oct 21 '13 at 10:48
  • I added @protocol sampleDelegate - (void)passValue:(id)selectedPorts; a end in SettingsViewController.h (the SecondViewController header file) – jrock007 Oct 21 '13 at 10:49
  • All are correct, you missing something, i have edited my answer. please look. – karthika Oct 21 '13 at 10:57
  • I think the problem might be that I don't have a UIViewController but a UITableViewController. – jrock007 Oct 21 '13 at 11:00
  • that is not a problem. – karthika Oct 21 '13 at 11:01
1
  • You have a list of ports in MasterViewController and you expect to use it in the SettingsViewController.
  • The MasterViewController can hold this list and SettingsViewController should have an access to it.

In SettingsViewController, have a setSelectedPort method:

@property (nonatomic, retain) id selectedPorts

- (void) setPorts:(id)selectedPorts;

The method saves the selected ports list into a property.

In MasterViewController, call the SettingsViewController and give it the list.

SettingsViewController *vc = [[SettingsViewController alloc] initWithNibName:@"SettingsViewController" bundle:nil];
[vc setSelectedPorts:yourValue]; 

When the list is modified inside the SettingsViewController, the list of ports contained in MasterViewController won't move even if you leave the SettingsViewController.

Community
  • 1
  • 1
Stéphane Bruckert
  • 21,706
  • 14
  • 92
  • 130
  • The problem is that the user enters the ports so I can't just call a method to change them – jrock007 Oct 21 '13 at 10:11
  • Not if you save the list instance (reference) into the `SecondViewController`. Then you could do whatever changes you wish on the list. Just save it as a property. Answer updated. – Stéphane Bruckert Oct 21 '13 at 10:23
0

There is nothing unusual in the getting result. By doing

MasterViewController *vc = [[MasterViewController alloc] initWithNibName:@"MasterViewController" bundle:nil];   
[vc setPorts:SelectedPorts];

You are creating a new instance of MasterViewController from your SecondViewController. This is not the same from which you navigated to the SecondViewController. So you wont get the expected result. Since you are setting the ports([vc setPorts:SelectedPorts]) to the newly created instance of the Master.

Instead of creating a new instance,just hold the reference of the MasterViewController in SecondViewController in a property and assign it before moving to second VC. As a beginner I suggested this way. But using delegate is the prefferred way passing data back.

Anil Varghese
  • 42,757
  • 9
  • 93
  • 110
0

Either use delegate methods to communicate with the master VC from the modal VC, or you could do something like this if you want to retrieive some manipulated objects from the modal VC.

Set the object(s) as properties in the modal view controller's .h-file (so they are public).

Using unwind segues, in the master VC, just do this:

-(IBAction)exitModalVC:(UIStoryboardSegue*)segue
{
    SomeObject *obj = ((YourModalVC*)segue.sourceViewController).someObject;

    //Do what you want with obj
}

EDIT:

This will only work if you are using unwind segue (which is a neat way of dismissing modal VC when using story board)

And you are using this, which is not unwind segues:

[[self presentingViewController] dismissViewControllerAnimated:YES completion:nil];
ullstrm
  • 9,812
  • 7
  • 52
  • 83
0

You were creating a new instance of the first view controller from the 2nd view controller not accessing the same instance of the original caller. That was the reason why while you could see the logs but data were not there when you got back to the original caller - your MasterViewController.

You need to use delegate method. Check my answer for this SO.

Community
  • 1
  • 1
user523234
  • 14,323
  • 10
  • 62
  • 102
0

This is problem related to object ownership. Follow the below steps:

As per understanding you want reverse value from "SecondViewController" to "FirstViewController"

Don't create new object of FirstViewController in SecondViewController, it will not work.

  1. Create object of "FirstViewController" in "SecondViewController.h" file. @property (nonatomic,strong) FirstViewController *firstViewController;

  2. When you navigate from FirstViewController to SecondViewController, please pass the "self". e.g. SecondViewController *vc = [[SecondViewController alloc] initWithNibName:@"SecondViewController" bundle:nil]; vc.firstViewController = self;

  3. If you want pass the reverse value to FirstViewController then in SecondViewController.m file. [self.firstViewController setPorts:SelectedPorts];

  4. And in FirstViewController.m refresh your controls with latest values.

Try above code will defiantly work as per your requirement.

Amol
  • 85
  • 5
  • when I add this in SecondViewController.h I get errors : @property (nonatomic,strong) MasterViewController *masterViewController; The errors are : "unknown type name MasterViewController" and "property with 'retain (or strong)' attributes must be of object type. MasterViewController is the name of my FirstViewController – jrock007 Oct 21 '13 at 10:16
  • Please import the same (MasterViewController)class in SecondViewController. #import "MasterViewController.h" – Amol Oct 21 '13 at 11:26
  • You creating object of MasterViewController thats why you need to import same class. #import "MasterViewController.h" – Amol Oct 21 '13 at 11:28