0

Let's say I have a UILabel on ViewControllerA and and UITextField on ViewControllerB. I want to go to ViewControllerB and input text then press a button to go back to ViewControllerA. The UILabel should now read whatever was typed in the UITextField.

I was able to accomplish the above by using NSUserDefaults and also using delegation. I am using Storyboards to do this. My question is about the segues used in the storyboards.

It seems when using delegation I must go to and from the storyboard with code and not visually connect the view controllers with a segue in order for the data to transfer. Here is the code when I press a button on my ViewController A:

- (IBAction)pressFirstButton:(id)sender {
UIStoryboard* sb = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
RBViewController2 *vc2 = [sb  instantiateViewControllerWithIdentifier:@"ViewController2"];
[vc2 setDelegate:self];
[self presentViewController:vc2 animated:YES completion:NULL];
}  

when passing the data back from ViewControllerB to ViewControllerA I do this:

- (IBAction)buttonSegueBackTo1:(id)sender {
NSString *sendThis = self.textFieldVC2.text;
[self.delegate passTextFieldInput:sendThis];
[self dismissViewControllerAnimated:YES completion:NULL];
}

No segue has been drawn between the view controllers and everything works fine. If I don't write this same code, and draw in a segue, the data won't pass backwards. However when I try passing data like this using NSUserDefaults I don't have to write the code to go to and from the view controllers. Instead I can simply connect the view controllers with a drawn segue. The weird thing is, if I'm trying to pass the data in using NSUserDefaults when manually coding the view controllers (an not drawing the segue) the data doesn't transfer.

I'm thinking maybe instead of writing the code in the -(IBAction) pressFirstButton:(id) sender method, I should be putting the code in the prepareForSegue method.

My question is why do drawn segues sometime cause data to be lost? Must all delegation be done without drawn segues? If NSUserDefaults require segues to transfer properly and delegation require code to transfer properly then if I have a view that requires both, it seems that NSUserDefaults will trump the delegation b/c the manual segue being used "resets" the view and only the NSUserDefaults data remains.

iOSAppGuy
  • 633
  • 7
  • 23

2 Answers2

1

Normal segues (any other than unwind segues) ALWAYS create new view controllers. So, if you're using anything other than an unwind segue to go back to A, you're really not "going back", you're creating a new ViewControllerA. Unwind segues aren't normally used in a case like you're presenting, just going back one controller, but you could.

This situation also isn't a good place to use user defaults. The Apple recommended way, is to use delegation, like you do in the code your question. The way you show, is probably the best way to do it, rather than using a segue to go back. You certainly could use a segue to go forward though, and in that case you would implement prepareForSegue: so you can set yourself as the delegate and/or pass any data forward.

rdelmar
  • 103,982
  • 12
  • 207
  • 218
  • Thanks! Should I think of segues as always creating "instances" of view controllers? And code like this: [self dismissViewControllerAnimated:YES completion:NULL] as being different from a segue because, unlike a segue, this is not creating an "instance" of a view controller, but instead it is going back to the controller from where it came from? Are you saying NSUserDefaults shouldn't be used here b/c I'm not setting a user default (like a name used when I always log in) but instead I'm abusing the class because I'm trying to have it do what can be done through delegation? – iOSAppGuy Feb 13 '13 at 21:15
  • @RyanBittorf, Yes, yes, and yes. Your understanding is correct. Except for unwind segues which do not create a new instance, and is a good way to go back through a complicated series of pushes and presents if you need to. – rdelmar Feb 13 '13 at 21:43
  • I didn't realize "unwind segues" existed. They sound pretty cool. When you reference them I didn't know there were something different from a normal segue. I will look into using them! – iOSAppGuy Feb 13 '13 at 22:15
1

Your question is a little dense to parse but I think you are asking if there is a way to get pass data through segues. The answer is yes, and much better than the workarounds you are trying.

In your button you would call:

[self performSegueWithIdentifier:@"scrollerSegue" sender:self];

This will trigger the method below and it is here that you can set the data on the destination viewController. You can set abstract properties on the destination viewController but you can't populate an UIKit elements (labels, imageViews, etc.) because they don't exist yet. Instead set properties and then in viewWillAppear in the destination viewController, do the set up as needed. (alternatively, instead of passing data, you could just set the delegate and then call methods on the delegate to get the data as needed).

For getting data back, using the delegate and calling methods on it seems to be the Apple recommended way of doing things.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
     if ([[segue identifier] isEqualToString:@"scrollerSegue"])
     {
         ScrollViewController * target = segue.destinationViewController;
         target.assetsArray = self.assetsArray;
         target.delegate = self;
     }
}
spring
  • 18,009
  • 15
  • 80
  • 160
  • Thanks! So it seems that segues should never really be drawn "backwards". If however if I'm inclined to use segues when passing data forward it makes sense to do so in the manner you have described here. I like the idea of the button simply calling the method of perforSegueWithIdentifier as you've described. You mention setting properties in viewWillAppear. I usually handle everything in viewDidLoad. Is there an advantage to using viewWillAppear over viewDidLoad? – iOSAppGuy Feb 13 '13 at 21:13
  • @RyanBittorf - When the `viewDidLoad` event is called, the UIKit elements may not yet be initialized/finalized (I've ran into this and had trouble figuring out why I couldn't set label text, etc.). – spring Feb 13 '13 at 21:19
  • so do you use viewDidLoad to load arrays and other "non visual elements" and use viewDidAppear to load visual elements such as UILabels UIImageViews etc? Is this what you are suggesting? Or do you just do everything in viewDidAppear and not really use viewDidLoad? – iOSAppGuy Feb 13 '13 at 21:24
  • @RyanBittorf - I use it for creating things from code that need to be created only once (since `viewDidLoad` is called only once while `ViewWillAppear` maybe be called multiple times in a viewController life cycle). – spring Feb 13 '13 at 21:34