使用代理和协议在两个UIViewController之间传递数据

26

我知道这个问题在这里已经被问答了很多次并得到了解答。但是我第一次处理这个问题,仍然不能完全理解如何实现它。下面是代码,我有一个委托方法,用于从 SecondViewController FirstViewController 传递数据。

FirstViewController.h

#import "SecondViewController.h"

@interface FirstViewController : UITableViewController<sampleDelegate> 
@end

FirstViewController.m

@interface FirstViewController ()

// Array in which I want to store the data I get back from SecondViewController.
@property (nonatomic, copy) NSArray *sampleData;
@end

@implementation FirstViewController
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
   SecondViewController *controller = [[SecondViewController alloc] init];          
   [self.navigationController pushViewController:controller animated:YES];
}
@end

SecondViewController.h

@protocol sampleDelegate <NSObject>
- (NSArray*)sendDataBackToFirstController;
@end

@interface SecondViewController : UITableViewController
@property (nonatomic, strong) id <sampleDelegate> sampleDelegateObject;
@end

SecondViewController.m

@interface SecondViewController ()
@property (strong, nonatomic) NSArray *dataInSecondViewController;
@end

@implementation SecondViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.dataInSecondViewController = [NSArray arrayWithObjects:@"Object1", @"Object2", nil];
}

- (NSArray*)sendDataBackToFirstController
{
    return self.dataInSecondViewController;
}
@end

我是否做得正确?我只想将self.dataInSecondViewController中的数据发送到FirstViewController,并将其存储在FirstViewControllerNSArray属性sampleData中。

不知何故,我无法在FirstViewController中访问sendDataBackToFirstController。我还需要实现哪些其他内容才能在那里访问sendDataBackToFirstController


1
你需要将第一个视图控制器设置为第二个视图控制器的代理。因此,第一个视图控制器需要实现第二个视图控制器的代理方法。然后,在第二个视图控制器触发事件时从第一个视图控制器调用该方法。根据您的情况,不清楚您是想要有数据源还是代理。如果您将第二个视图控制器用作第一个视图控制器的数据源,则是第一个视图控制器请求数据。但是,如果您只是想在第二个视图控制器中发生某些事件后将值返回给第一个视图控制器,则它属于代理。那么,您需要将返回类型更改为void,并将数据作为参数传递。 - Anupdas
我在我的第一个视图控制器的didSelectRow...中尝试执行controller.delegate = self。但是,一些原因导致controller无法找到委托对象。到目前为止,我的代码是否正确? - tech_human
请遵循@gdavis和art的答案。 - Anupdas
@NANNAV - 不确定为什么这个问题被认为是重复的。我在我的问题最初的开头就提到过这个问题已经有答案了,但这个问题是特定于我的实现。那里的答案对我实现代码没有太大帮助,所以我才开始另一个问题。 - tech_human
除了协议和委托之外,还有一种更简单易行的选择,那就是块。 - Leena
3个回答

15

还不太对。首先需要在第一个视图控制器中分配委托属性,这样第二个视图控制器才知道要向哪个对象发送信息。

FirstViewController.m

controller.delegate = self;

其次,你的委托方法的发送和接收顺序是相反的。你将它设置为期望在第一个控制器上调用sendDataBackToFirstController并由第二个控制器处理。在委托模式中,应该是SecondViewController发送消息并可选择使用该方法发送数据。因此,你应该更改委托声明为以下内容:

@protocol sampleDelegate <NSObject>
- (void)secondControllerFinishedWithItems:(NSArray* )newData;
@end

那么,当你的SecondViewController完成任务并需要通知其代理时,应该这样做:

然后,当您的 SecondViewController 完成任务并需要通知其委托对象时,应执行以下操作:

// ... do a bunch of tasks ...
// notify delegate
if ([self.delegate respondsToSelector:@selector(secondControllerFinishedWithItems:)]) {
    [self.delegate secondControllerFinishedWithItems:arrayOfNewData];
}

在这里,我添加了一个额外的if语句来检查委托是否会响应我们想要发送的方法,然后再实际发送它。如果我们的协议中有可选的方法并且没有这个if语句,应用程序将崩溃。

希望这能帮到你!


你和 @art 的解释对我在理解协议和代理的整个流程方面帮助很大。我跟随了你们的代码实现了代理,也得到了我想要的结果。我将代理属性从 strong 改为 weak 来避免保留环问题。 - tech_human

4

请按照以下步骤:

1. 打开FirstViewController.h文件。

   #import "SecondViewController.h"

   @interface FirstViewController : UITableViewController<sampleDelegate> 
   @end

FirstViewController.m

  @interface FirstViewController ()

  // Array in which I want to store the data I get back from SecondViewController.
  @property (nonatomic, copy) NSArray *sampleData;
  @end

 @implementation FirstViewController
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
 {
   SecondViewController *controller = [[SecondViewController alloc] init]; 
   controller.sampleDelegateObject=self;      
  [self.navigationController pushViewController:controller animated:YES];

 }

  //implementation of delegate method
  - (NSArray*)sendDataBackToFirstController
{
  return self.dataInSecondViewController;
}
 @end

SecondViewController.h

 @protocol sampleDelegate <NSObject>
- (NSArray*)sendDataBackToFirstController;
@end

@interface SecondViewController : UITableViewController
@property (nonatomic, strong) id <sampleDelegate> sampleDelegateObject;
@end
SecondViewController.m

 @interface SecondViewController ()
 @property (strong, nonatomic) NSArray *dataInSecondViewController;
 @end

 @implementation SecondViewController

 - (void)viewDidLoad
{
  [super viewDidLoad];
  self.dataInSecondViewController = [NSArray arrayWithObjects:@"Object1", @"Object2", nil];
   //calling the delegate method
  [sampleDelegateObject sendDataBackToFirstController];
}


  @end

1
协议的实现将在您想要实现的类中进行。 - Albin Joseph
谢谢您提供详细的带有代码的信息。 - Swap-IOS-Android

1

首先将代码

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

更改为

@property(nonatomic,weak)id<sampleDelegate>sampleDelegateObject;

以防止保留循环。搜索该词以获取解释。

其次,您的协议应该是:

@protocol sampleDelegate <NSObject>
- (void)sendDataBackToFirstController:(NSArray*)dataToSendBack;
@end

当您想要发送数据回来时,调用[self.sampleDelegateObject sendDataBackToFirstControoler:yourData];。第一个视图控制器必须在协议中实现这些方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接