Understanding the mechanism when passing data back from a second view controller to main view controller

StackOverflow https://stackoverflow.com/questions/21506809

I'm currently trying to have a better understanding on how the mechanisms of passing data between controllers work and I'm a little confused especially when passing data back from a second view controller to the main view controller.

This is what I have that works but don't fully understand. I have two view controllers, in the first one I have a button that when clicked it basically goes to the second view controller and a label which shows a message sent from the second view controller. In the second view controller I have a button and a textField, the button basically sends whatever is in the textfield to the label in main view controller.

Here is the code...

// FirstVC.h

#import <UIKit/UIKit.h>
#import "SecondVC.h"
@interface FirstVC : UIViewController <passNames>

@property (nonatomic, strong) NSString* firstNameString;
@property (weak, nonatomic) IBOutlet UILabel *firstNameLabel;

@end

//FirstVC.m

#import "FirstVC.h"

@implementation FirstVC

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue identifier]isEqualToString:@"secondController"])
    {
        UINavigationController *navController = segue.destinationViewController;
        SecondVC *vc2 =  (SecondVC*)navController.topViewController;
        [vc2 setDelegate:self];
    }
}
-(void)viewWillAppear:(BOOL)animated
{
    self.firstNameLabel.text = _firstNameString;
}

-(void)setFirstName:(NSString *)firstName
{
    _firstNameString = firstName;
}
@end

//SecondVC.h

#import <UIKit/UIKit.h>

@protocol passNames <NSObject>
-(void)setFirstName:(NSString*)firstName;
@end

@interface SecondVC : UIViewController

@property (retain)id <passNames> delegate;

- (IBAction)send:(UIBarButtonItem *)sender;

@property (nonatomic, strong) NSString *firstNameString;
@property (weak, nonatomic) IBOutlet UITextField *firstNameText;
@end

//SecondVC.m

#import "SecondVC.h"
#import "FirstVC.h"

@interface SecondVC ()

@end

@implementation SecondVC

- (IBAction)send:(UIBarButtonItem *)sender
{
    _firstNameString = _firstNameText.text;
    [[self delegate]setFirstName:_firstNameString];
    [self dismissViewControllerAnimated:YES completion:nil];
}
@end

Can someone explain how the prepareForSegue method works in the above code? The reason for this question is because I added an NSLog and it looks like this method is only called in the transition from main view controller to the second controller. Why is this method needed if it is not called when transitioning from second view controller to main view controller which in my case is what I'm doing? It makes sense to use it when passing data from main view controller to a second controller not on the case shown above.

Can some explain the whole mechanism when passing data back to the main view controller?

FYI, I do understand about protocols and delegation.

Thanks a lot.

有帮助吗?

解决方案 2

Your goal is to hand back the data, like this:

[[self delegate] setFirstName:_firstNameString];

But you can't do that unless you know who to send setFirstName: to, and the compiler won't let you do it unless you guarantee that whoever you are sending setFirstName: to can accept that message.

That is what prepareForSegue prepares. FirstVC has declared that it adopts the passNames protocol, which means that it implements setFirstName:. And now you are saying:

[vc2 setDelegate:self];

...where self is the FirstVC instance. This solves both problems at once. The SecondVC instance (vc2) now has a delegate (the FirstVC instance), it is the right object to send the info back to, and because its delegate is declared as adopting passNames, we know that SecondVC can actually send setFirstName: to that delegate.

Now to the heart of your actual question: The reason for doing this in prepareForSegue is merely that this is the only moment when the FirstVC instance and the SecondVC instance "meet" one another! There is no other moment when the FirstVC instance has a reference to the SecondVC instance so as to be able to call setDelegate on it in the first place. If you weren't using segues and storyboards, the FirstVC would simply create the SecondVC instance directly - and would set itself as its delegate, just as you do:

SecondVC *vc2 = [SecondVC new];
UINavigationController *nav = [
    [UINavigationController alloc] initWithRootViewController: vc2];
[vc2 setDelegate:self];
[self presentViewController: nav animated: YES completion: nil];

This is one reason I don't like storyboards: they muddy the story. It's all so simple and obvious when you don't use them and just do everything directly like this.

其他提示

In your case, you are setting your delegate method of the second view controller to self in mainViewController in you prepareForSegue. This means that apart from navigating to the SecondViewController, you are implementing the callback mechanism in your main view controller, so that your delegate method gets called when the value is passed from the second view controller and this delegate method collects the value as a parameter to handle it in the main View Controller. You might have set the delegate of VC2 as self inn your prepareForSegue because you are creating the instance of VC2 in this method to navigate to the second controller.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top