我有两个视图控制器, firstViewController 和 secondViewController 。我正在使用此代码切换到我的secondViewController(我也传递一个字符串):
secondViewController *second = [[secondViewController alloc] initWithNibName:nil bundle:nil];
second.myString = @"This text is passed from firstViewController!";
second.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:second animated:YES];
[second release];
然后我在secondViewController中使用此代码切换回firstViewController:
[self dismissModalViewControllerAnimated:YES];
所有这一切都很好。我的问题是,如何将数据传递给firstViewController?我想从secondViewController传递一个不同的字符串到firstViewController。
答案 0 :(得分:141)
您需要使用委托协议......以下是如何执行此操作:
在secondViewController的头文件中声明一个协议。它应该是这样的:
#import <UIKit/UIKit.h>
@protocol SecondDelegate <NSObject>
-(void)secondViewControllerDismissed:(NSString *)stringForFirst
@end
@interface SecondViewController : UIViewController
{
id myDelegate;
}
@property (nonatomic, assign) id<SecondDelegate> myDelegate;
不要忘记在您的实现(SecondViewController.m)文件中合成myDelegate:
@synthesize myDelegate;
在FirstViewController的头文件中,通过执行以下操作订阅SecondDelegate协议:
#import "SecondViewController.h"
@interface FirstViewController:UIViewController <SecondDelegate>
现在,当您在FirstViewController中实例化SecondViewController时,您应该执行以下操作:
// If you're using a view controller built with Interface Builder.
SecondViewController *second = [[SecondViewController alloc] initWithNibName:"SecondViewController" bundle:[NSBundle mainBundle]];
// If you're using a view controller built programmatically.
SecondViewController *second = [SecondViewController new]; // Convenience initializer that uses alloc] init]
second.myString = @"This text is passed from firstViewController!";
second.myDelegate = self;
second.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:second animated:YES];
[second release];
最后,在第一个视图控制器(FirstViewController.m)的实现文件中,为SecondViewControllerDismissed实现SecondDelegate的方法:
- (void)secondViewControllerDismissed:(NSString *)stringForFirst
{
NSString *thisIsTheDesiredString = stringForFirst; //And there you have it.....
}
现在,当您要关闭第二个视图控制器时,您想要调用第一个视图控制器中实现的方法。这部分很简单。您只需在第二个视图控制器中,在解除代码之前添加一些代码:
if([self.myDelegate respondsToSelector:@selector(secondViewControllerDismissed:)])
{
[self.myDelegate secondViewControllerDismissed:@"THIS IS THE STRING TO SEND!!!"];
}
[self dismissModalViewControllerAnimated:YES];
委托协议非常非常有用,非常有用。熟悉它们对你有好处:)
NSNotifications是另一种方法,但作为一种最佳实践,当我想跨多个viewControllers或对象进行通信时,我更喜欢使用它。如果您对使用NSNotifications感到好奇,这是我之前发布的答案:Firing events accross multiple viewcontrollers from a thread in the appdelegate
编辑:
如果要传递多个参数,则dismiss之前的代码如下所示:
if([self.myDelegate respondsToSelector:@selector(secondViewControllerDismissed:argument2:argument3:)])
{
[self.myDelegate secondViewControllerDismissed:@"THIS IS THE STRING TO SEND!!!" argument2:someObject argument3:anotherObject];
}
[self dismissModalViewControllerAnimated:YES];
这意味着您的firstViewController中的SecondDelegate方法实现现在看起来像:
- (void) secondViewControllerDismissed:(NSString*)stringForFirst argument2:(NSObject*)inObject1 argument3:(NSObject*)inObject2
{
NSString thisIsTheDesiredString = stringForFirst;
NSObject desiredObject1 = inObject1;
//....and so on
}
答案 1 :(得分:40)
我可能在这里不合适,但我开始更喜欢块语法到非常详细的委托/协议方法。如果从vc1创建vc2,则在vc2上有一个属性,你可以从vc1设置一个块!
@property (nonatomic, copy) void (^somethingHappenedInVC2)(NSString *response);
然后,当你想告诉vc1 vc2中发生的事情时,只需执行你在vc1中定义的块!
self.somethingHappenedInVC2(@"Hello!");
这允许您将数据从vc2发送回vc1。就像魔术一样。 IMO,这比协议更容易/更清洁。块很棒,需要尽可能地接受。
编辑 - 改进示例
假设我们有一个mainVC,我们想要暂时提供一个modalVC来获取用户的一些输入。为了从mainVC呈现modalVC,我们需要在mainVC中分配/ init它。很基本的东西。好吧,当我们创建这个modalVC对象时,我们还可以在其上设置一个块属性,以便我们在两个vc对象之间轻松进行通信。那么让我们从上面举例,并将以下属性放在modalVC的.h文件中:
@property (nonatomic, copy) void (^somethingHappenedInModalVC)(NSString *response);
然后,在我们的mainVC中,在我们分配/初始化一个新的modalVC对象之后,你可以像这样设置modalVC的block属性:
ModalVC *modalVC = [[ModalVC alloc] init];
modalVC.somethingHappenedInModalVC = ^(NSString *response) {
NSLog(@"Something was selected in the modalVC, and this is what it was:%@", response);
}
所以我们只是设置块属性,并定义执行该块时会发生什么。
最后,在我们的modalVC中,我们可以拥有一个由dataSource字符串数组支持的tableViewController。一旦选择了行,我们就可以这样做:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *selectedString = self.dataSource[indexPath.row];
self.somethingHappenedInModalVC(selectedString);
}
当然,每次我们在modalVC中选择一行时,我们将从mainVC中获取NSLog线路的控制台输出。希望有所帮助!
答案 2 :(得分:4)
嗯,寻找通知中心并在通知中传回信息。 here is apples take on it - 我个人采用这种方法,除非任何人有任何其他建议
答案 3 :(得分:2)
在第二个视图控制器中定义委托协议,并使第一个委托协议成为第二个视图控制器的委托。