使用Segue在视图控制器之间传递数据

我是iOS新手。 我面临着在ViewControllers之间传递数据的问题。 我有三个viewController(view_1,view_2和view_3)。

在这里我的设置: –

  • selectview_1
  • 推view_2
  • 推view_3

我想发送'view_1'的ViewController引用(id)到'view_3'。 所以我包括include "view_3" ,并将值设置为“view_3”的variables(使用view_3 *v3=[[view_3 alloc] init ]; v3.reference=self; )。 在控制台中显示:

视图控制器: – ; <ViewController:0x89e9540>

在“view_1”中,而在“view_3”中,在控制台中显示

视图控制器(null)

但是,当我使用'view_2'传递这个数据的工作。 但是,如何? 我想知道这种行为,有没有解决scheme来创build这个?

请帮忙。

通过覆盖方法prepareForSegue:sender:来实现在触发segue时“将数据传递给目标控制器”。

通常,您将数据而不是源视图控制器传递到目标视图控制器。 “数据”可能是您的应用程序“模型”的某个方面。 这是一个像“用户”的对象,或者是一个包含“用户”等的数组。

目标视图控制器应该有任何有关视图控制器的知识。 这意味着,目标视图控制器不需要导入源视图控制器的标题。

另一方面, 视图控制器可能知道目的视图控制器的具体类或者目的视图控制器的类,因此将导入目的视图控制器的标题。

请参阅: 在触发Segue时configuration目标控制器

如果您需要源和目标之间的某种“通信协议”,则可以使用委托与其他视图控制器进行通信。 这涉及到@protocol的定义(例如有一个方法doneButton )和一个在目标视图控制器中定义的属性delegate 。 协议应该在目标视图控制器的头部中定义,如果它特定于目标视图控制器。 通常,您从目标控制器的angular度定义tho协议,而不是从源控制器的要求中定义。

源视图控制器然后创build一个委托(除非,它本身已经),并设置目标视图控制器的delegate 。 目标视图控制器将把委托方法发送给委托,委托处理它。

现在,将VC_A中的“数据”传递给VC_B应该是直接的。 你应该阅读几个使用prepareForSegue:sender:例子prepareForSegue:sender: 例如, 目的地视图控制器可以具有代表它应该显示的事物的属性data 。 源视图控制器必须在prepareForSegue:sender:设置此属性。

从VC_A通过VC_B到VC_C的数据传递也应该是直接的。

注意:每个视图控制器可以定制 (分离,修改,准备,分片,转换等) data ,使其成为下一个视图控制器的合适data


如果VC_C需要在其源视图控制器VC_B中不可用的数据,那么有几种方法可以解决这个问题。 但是,这通常是devise不好的标志。

可以有一个全球化的应用程序模型。 假设你的“应用模型”是一个Documenttypes的对象。 假设,在任何时候只有一个应用程序模型的实例。 然后,该模型是一个“单身人士”, 可以从您的应用程序的任何地方访问,如下所示:

 Document* document = [Document sharedDocument]; 

但是,获取模型实例的首选方法是在需要访问它的第一个视图控制器中,在这种情况下是:VC_A。

然后,VC_A将Document实例传递给下一个视图控制器VC_B。 而VC_B将文档对象传递给VC_C。

你应该阅读官方文档“ 视图控制器编程指南iOS ”。


例1

假设你有一个“用户”列表。 该列表应显示在一个表视图控制器中,并且还应该有一个详细视图,显示一个用户的详细信息。

表视图控制器将有一个“数据”属性的users

UsersTableViewController.h中

 @interface UsersTableViewController : UIViewController @property (nonatomic, readonly) NSArray* users; @end 

(严格来说,这个user属性并不需要公开,例如,如果表视图在内部获得用户列表本身,则不需要从外部访问它。

“users”数组是表格视图的数据 ,应该按行显示。 每行显示一个用户的“摘要”。

应该在详细视图控制器中显示用户的更多细节。 详细视图控制器的数据是用户types的单个用户。

当用户在表格视图中选中某一行时,将显示详细视图控制器。 在显示之前,表视图控制器必须configuration详细视图控制器:表视图控制器将详细视图控制器的“数据属性”分配给当前select的用户 。 因此,详细视图控制器应该有一个公共属性user

 @interface UserViewController : UIViewController @property (nonatomic) User* user; @end 

表视图控制器在prepareForSegue:sender:configuration详细视图控制器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

第二个例子比较复杂,使用“委托”作为在控制器之间build立通信的手段。

警告:

这不是一个完整的例子。 这个例子的目的是演示如何使用“授权”。 如示例中所示的数据任务的全function实现将需要更多的努力。 在这样的情况下,“授权”将是实现这一目标的最佳方法(恕我直言)。

假设我们想要

  • 显示一个用户
  • 修改(编辑)用户
  • 新build一个用户,和
  • 删除一个用户

从详细视图中。

这些“数据任务”不应该由详细视图控制器本身执行 ,而是委托人负责这些数据任务。

这些数据操作应由委托人处理:

 @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方法(创build,读取,更新,删除)。

同样,我们不希望Detail View Controller 本身执行这些数据方法,而是由实现UserDataSourceDelegateProtocol的实例执行。 详细视图控制器具有此代理的属性,并将这些“数据任务”发送给代理。

可能有几个详细视图控制器,抽象类UserViewControllerBase所有子类,它们处理显示编辑创build任务。 删除用户可以在表格视图和“显示用户”视图控制器中执行:

  • ShowUserViewController
  • EditUserViewController
  • NewUserViewController

例如, EditUserViewController会发送viewController:dismissWithUpdatedUser:当用户viewController:dismissWithUpdatedUser: “后退”button,并且用户修改了用户对象。 现在,代表可以允许或不允许解除详细视图。 例如有validation错误时,它可能会禁止它。

UserDataSourceDelegateProtocol协议可以在根视图控制器,例如表视图控制器中实现。 然而,一个单独的课程,其唯一的责任是处理数据任务可能更合适。 在下面的示例中,表视图控制器也将是这个数据处理程序。

UserDataSourceDelegateProtocol可以在额外的头文件中定义。

UsersTableViewController.m中

 #import "UserDataSourceDelegateProtocol.h" #import "ShowUserViewController.h" @interface UsersTableViewController () <UserDataSourceDelegateProtocol> @property (nonatomic, readonly) NSArray* users; @end // This delegate will be called when the detail view controller request // the user object which shall be displayed. - (User*) viewControllerUser:(UserViewControllerBase*)viewController { return [self.users objectInListAtIndex:[self.tableView indexPathForSelectedRow].row]; } 

这里,表视图控制器configuration显示用户详细信息视图控制器:

 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([segue.identifier isEqualToString:UserShowSegueID]) { ShowUserViewController* showViewController = segue.destinationViewController; showViewController.delegate = self; // Data Source Handler is self } } 

“编辑用户”视图控制器通常是“显示用户”视图控制器的目标视图控制器,当用户选中“编辑”button时可以查看该控制器。

“显示用户”视图控制器将设置“编辑用户”视图控制器的委托获取相同的委托:

ShowUserViewController.m中

 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([segue.identifier isEqualToString:UserEditSegueID]) { EditUserViewController* editViewController = segue.destinationViewController; editViewController.delegate = self.delegate; // pass through the data source hanlder } } 

数据委托可以处理更新的用户,如下所示:

UsersTableViewController.m中

 - (void) viewController:(UserViewControllerBase*)viewController dismissWithUpdatedUser:(User*)user { if (/* is valid user and can be saved */) { [viewController.presentingViewController dismissViewControllerAnimated:YES completion:nil]; } } 

YouTube上的这个Swift项目帮助我终于明白了如何做到这一点。

我沿着类似的路线build立了一个简单的例子。 在文本字段中写入一些文本,按下button,将文本放入下一个视图控制器的标签中。

设置故事板

在这里输入图像说明

这不是很困难。 在Interface Builder中创build故事板布局。 你可以控制点击button并拖到第二个视图控制器。

第一视图控制器

第一个视图控制器的代码是

 import UIKit class FirstViewController: UIViewController { @IBOutlet weak var textField: UITextField! // This function is called before the segue override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { // get a reference to the second view controller let secondViewController = segue.destinationViewController as! SecondViewController // set a variable in the second view controller with the String to pass secondViewController.receivedString = textField.text! } } 

第二视图控制器

而第二个视图控制器的代码是

 import UIKit class SecondViewController: UIViewController { @IBOutlet weak var label: UILabel! // This variable will hold the data being passed from the First View Controller var receivedString = "" override func viewDidLoad() { super.viewDidLoad() // Used the text from the First View Controller to set the label label.text = receivedString } } 

别忘了

  • 连接UITextFieldUILabel的sockets。
  • 将第一个和第二个视图控制器设置为IB中合适的Swift文件。

将数据传递到第三个视图控制器的过程将是相同的。

你有一个解决scheme,但不是最正确的方法。

ViewController3.h

 -(void)getUser:(NSString *)strPassedUser; 

去你的ViewController3.m和@interface上面添加一个像这样的variables

 NSString *recievingVariable ; 

那么在ViewController3.m里面的一些地方

 -(void)getUser:(NSString *)strPassedUser { recievingVariable = strPassedUser; } 

ViewController1和导入ViewController3然后这样做..

 ViewController3 * vc3 = [ViewController3 alloc]getUser :@"me"]; 

在这种情况下,你的函数getUser将被调用,你将得到receivingVariable= mevariablesreceivingVariable= me

更好更简单的解决scheme

 UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"webView"]; webView = (WebViewController *)vc; webView.strWebLink = @"http://www.Google.com/"; [self.navigationController showViewController:vc sender:self]; 

使用Singleton模式:

软件工程中的Singleton模式是一种devise模式,它确保一个类只有一个实例,并提供一个全局访问点。

由于它具有唯一的实例,所以在整个应用程序/名称空间中共享类variables和方法。

例:

 class Singleton { static let sharedInstance = Singleton() var studentId = 1281 } 

你可以在你的应用程序的任何地方使用它:

 var studentId = Singleton.sharedInstance.studentId print("Student Id: \(studentId)")