当触发segue时,“将数据传递给目标控制器”将通过重写方法
prepareForSegue:sender:
来实现。
通常情况下,您将
数据而不是源视图控制器传递给目标视图控制器。 “数据”可能是您的应用程序“模型”的某个方面。它是像“用户”这样的对象,或者可能是包含“用户”等内容的数组。
目标视图控制器不应该了解
源视图控制器。这意味着,目标视图控制器不需要导入源视图控制器的头文件。
另一方面,
源视图控制器
可以了解
目标视图控制器的具体类或目标视图控制器的
基本类,因此将导入目标视图控制器的头文件。
请参阅:
在触发Segue时配置目标控制器
如果您需要在源和目标之间建立某种“通信协议”,您可以使用
委托与其他视图控制器进行通信。这涉及到定义一个@protocol(例如,有一个方法
doneButton
),以及在目标视图控制器中定义的一个属性
delegate
。如果该协议是特定于目标视图控制器的,则应在目标视图控制器的头文件中定义该协议。通常,您应该从目标控制器的角度定义协议,而不是从源控制器的要求出发。
然后,源视图控制器创建一个代理(除非它本身已经是代理),并设置目标视图控制器的
delegate
。目标视图控制器将把委托方法发送给代理,由代理处理。
现在,从VC_A传递“数据”到VC_B应该很简单。您应该阅读一些使用
prepareForSegue:sender:
的示例。例如,
目标视图控制器可能具有一个表示其应显示的
内容的属性
data
。源视图控制器必须在
prepareForSegue:sender:
中设置此属性。
Passing data from VC_A over VC_B to VC_C should be straight forward as well.
注意:每个视图控制器都可以定制其数据,以使其成为下一个视图控制器的合适数据。
如果VC_C需要其源视图控制器VC_B中没有的数据,则有几种方法可以解决此问题。但是,这通常是设计不良的标志。
您可以拥有一个应用程序模型,它是全局的。假设您的“应用程序模型”是类型为Document的对象。假设在任何时候只有一个该应用程序模型的实例。那么,该模型是一个“单例”,可以像这样从应用程序的任何地方访问:
Document* document = [Document sharedDocument];
然而,获取一个模型实例的首选方法是在需要访问它的第一个视图控制器中,这种情况下是 VC_A。
接着,VC_A将一个Document
实例传递给下一个视图控制器 VC_B。而VC_B又将文档对象传递给VC_C。
您应该阅读官方文档 "View Controller Programming Guide for iOS"。
示例1
假设您有一个名为“用户”的列表。该列表应在表视图控制器中显示,并且还应该有一个详细视图,显示一个用户的详细信息。
表视图控制器将具有一个“data”属性users
:
在UsersTableViewController.h中:
@interface UsersTableViewController : UIViewController
@property (nonatomic, readonly) NSArray* users;
@end
严格来说,这个user
属性不需要公开。例如,如果表视图内部自己获取用户列表,则没有必要从外部访问它。
"users"数组是表视图的数据,应该以行显示。每一行显示一个用户的“摘要”。
用户的更多详细信息应该在详细视图控制器中显示。详细视图控制器的数据是单个类型为User
的用户。
当用户在表视图中点击某一行时,将显示详细视图控制器。在显示之前,表视图控制器必须配置详细视图控制器:表视图控制器将当前选定的用户分配给详细视图控制器的“数据属性”。因此,详细视图控制器应该有一个公共属性user
:
@interface UserViewController : UIViewController
@property (nonatomic) User* user;
@end
"The table view controller在
prepareForSegue:sender:
中配置详细视图控制器:"
"
UsersTableViewController.m中:"
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:@"ShowUserDetails"]) {
UserViewController* userViewController = [segue destinationViewController];
userViewController.user = [self.users objectInListAtIndex:[self.tableView indexPathForSelectedRow].row];
}
}
例子2
第二个例子更加复杂,使用“委托”作为一种在控制器之间建立通信的手段。
注意:
这不是一个完整的例子。本例目的在于演示如何使用“委托”。实现像例子中所示的数据任务的全功能实现将需要更多的努力。在这种情况下,“委托”将是最常用的方法来完成这项任务(依我看)。
假设我们想要:
- 显示用户
- 修改(编辑)用户
- 创建新用户,并且
- 删除用户
从详细视图中进行这些“数据任务”不应该由详细视图控制器自己执行,而是由代理负责这些数据任务。
这些数据操作应该由代理处理:
@protocol UserDataSourceDelegateProtocol <NSObject>
- (User*) viewControllerUser:(UserViewControllerBase*)viewController;
- (void) viewController:(UserViewControllerBase*)viewController dismissWithUpdatedUser:(User*)user;
- (void) viewController:(UserViewControllerBase*)viewController dismissWithDeletedUser:(User*)user;
- (void) viewController:(UserViewControllerBase*)viewController dismissWithCreatedUser:(User*)user;
@end
这个协议反映了基本的CRUD方法(创建、读取、更新、删除)。
再次强调,我们不希望详细视图控制器“自己”执行这些数据方法,而是由实现UserDataSourceDelegateProtocol的实例执行。详细视图控制器具有此委托的属性,并将这些“数据任务”发送到委托。
可能会有几个详细视图控制器,都是抽象类UserViewControllerBase的子类,处理显示、编辑和创建任务。用户删除可以在表视图和“显示用户”视图控制器中执行:
- ShowUserViewController
- EditUserViewController
- NewUserViewController
例如,当用户点击“返回”按钮并且用户修改了用户对象时,EditUserViewController将发送viewController:dismissWithUpdatedUser:消息。现在,委托可能允许或不允许关闭详细视图。例如,在存在验证错误时,它可能会禁止关闭。
UserDataSourceDelegateProtocol
协议可以在根视图控制器中实现,例如表视图控制器。然而,一个专门负责处理数据任务的独立类可能更合适。在下面的示例中,表视图控制器也将成为此数据处理程序。
UserDataSourceDelegateProtocol
可以在额外的头文件中定义。
在 UsersTableViewController.m 中:
#import "UserDataSourceDelegateProtocol.h"
#import "ShowUserViewController.h"
@interface UsersTableViewController () <UserDataSourceDelegateProtocol>
@property (nonatomic, readonly) NSArray* users;
@end
- (User*) viewControllerUser:(UserViewControllerBase*)viewController {
return [self.users objectInListAtIndex:[self.tableView indexPathForSelectedRow].row];
}
在这里,表视图控制器配置显示用户详细信息视图控制器:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:UserShowSegueID])
{
ShowUserViewController* showViewController = segue.destinationViewController;
showViewController.delegate = self;
}
}
“编辑用户”视图控制器通常是“显示用户”视图控制器的目标视图控制器,当用户点击“编辑”按钮时会查看该控制器。
“显示用户”视图控制器将为“编辑用户”视图控制器设置委托,并获取相同的委托:
在
ShowUserViewController.m 文件中。
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:UserEditSegueID])
{
EditUserViewController* editViewController = segue.destinationViewController;
editViewController.delegate = self.delegate;
}
}
数据代理可以按照以下方式处理更新的用户:
在UsersTableViewController.m中:
- (void) viewController:(UserViewControllerBase*)viewController
dismissWithUpdatedUser:(User*)user {
if () {
[viewController.presentingViewController dismissViewControllerAnimated:YES
completion:nil];
}
}