了解将数据从第二个视图控制器传回主视图控制器时的机制

时间:2014-02-02 03:51:33

标签: ios objective-c uiviewcontroller delegation

我目前正在努力更好地理解控制器之间传递数据的机制是如何工作的,我有点困惑,尤其是当将数据从第二个视图控制器传回主视图控制器时

这是我的工作,但不完全理解。我有两个视图控制器,在第一个我有一个按钮,当点击它时,它基本上转到第二个视图控制器和一个标签,显示从第二个视图控制器发送的消息。在第二个视图控制器中,我有一个按钮和一个textField,该按钮基本上将文本字段中的任何内容发送到主视图控制器中的标签。

这是代码......

// 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

有人可以解释一下prepareForSegue方法在上面的代码中是如何工作的吗?这个问题的原因是因为我添加了一个NSLog,看起来这个方法只在从主视图控制器到第二个控制器的转换中被调用。如果在从第二个视图控制器转换到主视图控制器时没有调用它,为什么需要这个方法?在我的情况下,我正在做什么?将数据从主视图控制器传递到第二个控制器而不是上面显示的情况时,使用它是有意义的。

有些人可以解释将数据传回主视图控制器时的整个机制吗?

仅供参考,我确实了解协议和授权。

非常感谢。

2 个答案:

答案 0 :(得分:3)

在您的情况下,您将在prepareForSegue中的mainViewController中将第二个视图控制器的委托方法设置为self。这意味着除了导航到SecondViewController之外,您还在主视图控制器中实现了回调机制,以便在从第二个视图控制器传递值时调用您的委托方法,并且此委托方法将值作为参数收集到在主View Controller中处理它。您可能已将VC2的委托设置为prepareForSegue的self,因为您正在此方法中创建VC2实例以导航到第二个控制器。

答案 1 :(得分:1)

您的目标是交回数据,如下所示:

[[self delegate] setFirstName:_firstNameString];

但你不能这样做,除非你知道发送setFirstName:,并且除非你保证,编译器不会你这样做您发送setFirstName:的任何人都可以接受该消息。

这是prepareForSegue准备的。 FirstVC声明它采用passNames协议,这意味着它实现了setFirstName:。现在你说:

[vc2 setDelegate:self];

...其中self FirstVC实例。这一次解决了这两个问题。 SecondVC实例(vc2)现在有一个委托(FirstVC实例),它是将信息发送回的正确对象,因为它的委托被声明为采用{{1我们知道SecondVC实际上可以向该委托发送passNames

现在回答实际问题的核心:在setFirstName:中执行此操作的原因仅仅是这是FirstVC实例和SecondVC实例彼此“会面”的唯一时刻! FirstVC实例没有其他时刻可以引用SecondVC实例,以便能够首先在其上调用prepareForSegue。如果您没有使用segues和storyboard,FirstVC将直接创建SecondVC实例 - 并将自己设置为其委托,就像您一样:

setDelegate

这是我不喜欢故事板的一个原因:他们把故事搞得一团糟。当你使用它们并且直接做这样的事情时,这一切都非常简单明了。