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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20017026/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 22:23:38  来源:igfitidea点击:

Passing data between View Controllers using Segue

iosuiviewcontrollersegue

提问by MAX

I am new to iOS. I am facing a problem passing the data between ViewControllers. I have three viewControllers (view_1 ,view_2 and view_3).

我是 iOS 新手。我面临在 ViewControllers 之间传递数据的问题。我有三个视图控制器(view_1、view_2 和 view_3)。

Here my setup:-

这是我的设置:-

  • Select view_1
  • pushes view_2
  • pushes view_3
  • 选择视图_1
  • 推动 view_2
  • 推动 view_3

I want to send the ViewController reference(id) of 'view_1' to 'view_3'. so i include include "view_3"in 'view_1' and set the value into the variable of 'view_3'( using view_3 *v3=[[view_3 alloc] init ]; v3.reference=self;). In the console it shows:

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

view controller :- ; <ViewController: 0x89e9540>

视图控制器:-; <视图控制器:0x89e9540>

in the 'view_1' but in the 'view_3', in console it shows

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

view controller (null)

视图控制器(空)

But when i used 'view_2' for passing this data its work. But how? I want to know this behaviour, And Is there any solution to creating this?

但是当我使用“view_2”传递这个数据时,它的工作。但是如何?我想知道这种行为,有没有办法解决这个问题?

please help.

请帮忙。

回答by CouchDeveloper

"Passing data to the destination Controller" when a segue is triggered will be achieved by overriding method prepareForSegue:sender:.

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

Generally, you pass dataand NOT the source view controller, to the destination view controller. "data" may be a certain aspect of your application "model". It's an object like "User", or perhaps an array containing "User", etc.

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

The destinationview controller shall nothave any knowledge of the sourceview controller. That means, the destination view controller does not need to import the header of the source view controller.

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

On the other hand, the sourceview controller mayhave knowledge of the concrete class of the destinationview controller or a baseclass of the destination view controller, and thus will import the header of the destination view controller.

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

See: Configuring the Destination Controller When a Segue is Triggered

请参阅:触发 Segue 时配置目标控制器

If you need some sort of "communication protocol" between the source and the destination, you might employ Delegationto communicate with other view controllers. This involves the definition of a @protocol (e.g. having a method doneButton) and a property delegatewhich is defined in the destination view controller. The protocol should be defined in the header of the destination view controller, if it's specificto the destination view controller. Usually, you define tho protocol from the view point of the destination controller, and not from the requirements of the source controller.

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

The source view controller then creates a delegate (unless, it itself is it already) and sets the delegateof of the destination view controller. The destination view controller will send the delegate methods to the delegate, and the delegate handles it.

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

Now, passing "data" from a VC_A to VC_B should be straight forward. You should read a few examples which use prepareForSegue:sender:. For example, the destinationview controller may have a property datawhich represents the thingit should display. The source view controller must set this property in prepareForSegue:sender:.

现在,将“数据”从 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_A 通过 VC_B 传递到 VC_C 也应该是直截了当的。

Note: Each view controller may tailor(separate, modify, prepare, slice, transform, etc.) itsdatato make it a suitable datafor the nextview controller.

注意:每个视图控制器5裁缝(单独的,修改,制备,切片,变换等)data使之成为适合data用于下一个视图控制器。



If VC_C needs data that is not available in its source view controller VC_B, then there are a couple of approaches to solve this. However, this is usually a sign of bad design.

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

You couldhave an application model, which is global. Suppose, your "application model" is an object of type Document. Suppose, at any time there is only oneinstance of that application model. Then, the model is a "Singleton", which couldbe accessed from anywhere in your app like so:

可以拥有一个应用程序模型,它是global。假设,您的“应用程序模型”是一个类型为 的对象Document。假设在任何时候都只有该应用程序模型的一个实例。然后,该模型是一个“单身人士”,可以从您的应用程序中的任何位置访问,如下所示:

Document* document = [Document sharedDocument];

However, the preferred way to get an instance of a model is in the firstview controller which requires access to it, in this case: VC_A.

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

Then, VC_A passes a Documentinstance to the next view controller VC_B. And VC_B passes the document object to VC_C.

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

You should read the official documentation "View Controller Programming Guide for iOS".

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



Example 1

示例 1

Suppose, you have a list "Users". The list should be displayed in a table view controller, and there should also be a detail view, showing details of one User.

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

The table view controller will have a "data" property users:

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

In UsersTableViewController.h:

UsersTableViewController.h 中

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

(Strictly, this userproperty doesn't need to be public. For example, if the table view internally obtains the list of users itself, there is not need to access it from outside.

(严格来说,这个user属性是不需要公开的,比如表视图内部自己获取了用户列表,就不需要从外部访问。

The "users" array is the dataof the table view which shall be displayed in rows. Each row shows a "summary" of a user.

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

More details of a user should be displayed in a detail view controller. The detail view controller's data is a single user of type User.

用户的更多详细信息应该显示在详细视图控制器中。详细视图控制器的数据是类型为 的单个用户User

When the user tabs a certain row in the table view, the detail view controller will be displayed. Before it will be displayed, the table view controller must configure the detail view controller: the table view controller assigns the detail view controller's "data property" the current selected user. Thus, the detail view controller should have a publicproperty user:

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

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

The table view controller configures the detail view controller in prepareForSegue:sender::

表视图控制器在以下位置配置详细视图控制器 prepareForSegue:sender:

In UsersTableViewController.m

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];
    }
}


Example 2

示例 2

The second example is more complex and uses "Delegation" as a means to establish a communication between controllers.

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

Caution:

警告:

This is not a complete example. The purpose of this example shall demonstrate how to use "Delegation". A full featured implementation of data tasks as shown in the example will require significant more effort. In this scenarios like these, "Delegation" will be the most preferred approach to accomplish this (IMHO).

这不是一个完整的例子。本示例的目的是演示如何使用“委托”。如示例中所示,数据任务的全功能实现将需要付出更多的努力。在这种情况下,“委派”将是实现此目的的最佳方法(恕我直言)。

Suppose we want to

假设我们想要

  • Show a User
  • Modify (edit) a User
  • Create New a User, and
  • Delete a User
  • 显示用户
  • 修改(编辑)用户
  • 创建新用户,以及
  • 删除用户

from within the detail view.

从详细视图中。

These "data tasks" shall not be performed by the detail view controller itself, instead a delegateis responsible for these data tasks.

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

These data actions shall be handled by the delegate:

这些数据操作应由代表处理:

@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

This protocol reflects the basic CRUD methods (Create, Read, Update, Delete).

该协议反映了基本的 CRUD 方法(创建、读取、更新、删除)。

Again, we don't want the Detail View Controller itselfto perform these data methods, but instead this will be performed by an instance implementing the UserDataSourceDelegateProtocol. The detail view controller has a property of this delegate, and it sends these "data tasks" to the delegate.

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

There may be several detail view controllers, all subclasses of abstract class UserViewControllerBasewhich handle the show, editand createtasks. Deletion of a user can be performed in the table view and in the "Show User" view controller:

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

  • ShowUserViewController
  • EditUserViewController
  • NewUserViewController
  • ShowUserViewController
  • EditUserViewController
  • NewUserViewController

For example The EditUserViewControllerwill send viewController:dismissWithUpdatedUser:when the user tabs the "back" button AND if the user has modified the user object. Now, the delegate may or may not allow to dismiss the detail view. It may disallow it when there are validation errors for example.

例如 TheEditUserViewControllerviewController:dismissWithUpdatedUser:在用户点击“后退”按钮时发送,并且如果用户修改了用户对象。现在,委托可能会也可能不会允许关闭详细信息视图。例如,当存在验证错误时,它可能会禁止它。

The UserDataSourceDelegateProtocolprotocol maybe implemented in the root view controller, the table view controller for example. However, a separate class whose sole responsibility is to handle data tasks may be more appropriate. In the sample below, the table view controller will also be this data handler.

UserDataSourceDelegateProtocol协议可以在根视图控制器中实现,例如表视图控制器。但是,单独负责处理数据任务的单独类可能更合适。在下面的示例中,表视图控制器也将是此数据处理程序。

The UserDataSourceDelegateProtocolmay be defined in an extra header.

所述UserDataSourceDelegateProtocol可在附加标题来限定。

In UsersTableViewController.m:

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];
}

Here, the Table View Controller configures the Show User Detail View Controller:

这里,Table View Controller 配置了 Show User Detail View Controller:

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

The "Edit User" view controller is usually a destination view controller of the "Show User" view controller, which gets viewed when the user tabs the "Edit" button.

“编辑用户”视图控制器通常是“显示用户”视图控制器的目标视图控制器,当用户点击“编辑”按钮时会被查看。

The "Show User" view controller will setup the delegate for the "Edit User" view controller gets the same delegate:

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

In ShowUserViewController.m

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

The data delegate may handle an updated user as follows:

数据委托可以按如下方式处理更新的用户:

In UsersTableViewController.m:

UsersTableViewController.m 中

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

回答by Suragch

This Swift projecton YouTube helped me to finally understand how to do this.

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

I set up a simple example along similar lines. Write some text in a text field, press the button, and it puts the text in a Label in the next View Controller.

我沿着类似的路线设置了一个简单的例子。在文本字段中写入一些文本,按下按钮,它会将文本放入下一个视图控制器的 Label 中。

Setup the storyboard

设置故事板

enter image description here

在此处输入图片说明

It's not very difficult. Create the storyboard layout in the Interface Builder. To make the segue you just controlclick on the button and drag over to the Second View Controller.

这不是很难。在界面生成器中创建故事板布局。要进行转场,您只需control单击按钮并拖动到第二个视图控制器。

First View Controller

第一个视图控制器

The code for the First View Controller is

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

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!
    }

}

Second View Controller

第二个视图控制器

And the code for the Second View Controller is

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

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
    }

}

Don't forget

不要忘记

  • Hook up the outlets for the UITextFieldand the UILabel.
  • Set the first and second View Controllers to the appropriate Swift files in IB.
  • 挂钩的出口UITextFieldUILabel
  • 将第一个和第二个视图控制器设置为 IB 中相应的 Swift 文件。

The process to pass the data on to a Third View Controller would be the same.

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

回答by naveen

ya there is a solution but not the most proper way .

雅有一个解决方案,但不是最合适的方法。

ViewController3.h

视图控制器3.h

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

go to your ViewController3.m and above the the @interface add a variable like this

转到您的 ViewController3.m 并在 @interface 上方添加一个像这样的变量

NSString *recievingVariable ;

then some where inside the ViewController3.m

然后在 ViewController3.m 里面的一些地方

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

ViewController1 and import ViewController3 then do like this ..

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

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

in this case your function getUserwill be called and you will get receivingVariable= me.

在这种情况下,您的函数getUser将被调用,您将获得receivingVariable= me.

回答by iPhone 7

Better and easy solution.

更好更简单的解决方案。

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];

回答by Alzayed

Use Singleton pattern:

使用单例模式:

The Singleton pattern in software engineering is a design pattern that ensure a class has only one instance, and provide a global point of access to it.

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

As it has a unique instance, class variables and methods are shared in entire application/namespace.

由于它有一个唯一的实例,类变量和方法在整个应用程序/命名空间中共享。

Example:

例子:

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

And you can use it anywhere in your App like this:

你可以在你的应用程序中的任何地方使用它,如下所示:

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

回答by Zumry Mohamed

in Swift 4.0

在 Swift 4.0 中

 // In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    let vc = segue.destination as! SecondViewController
    vc.username = self.username
}

Make sure

确保

segue.destinationis the real different here.

segue.destination是真正的不同在这里。