如何传递prepareForSegue:一个对象


357

我在地图视图中有很多注释(带有rightCalloutAccessory按钮)。该按钮将从此按钮执行mapview到一个按钮tableview。我想tableview根据单击哪个标注按钮来传递一个不同的对象(保存数据)。

例如:(全部组成)

  • 注解1(Austin)->传递数据obj 1(与Austin相关)
  • 注解2(达拉斯)->传递数据obj 2(与达拉斯相关)
  • 注解3(休斯敦)->传递数据obj 3,依此类推...(你明白了)

我能够检测到单击了哪个标注按钮。

我正在使用prepareForSegue:将数据obj传递到目的地ViewController。由于无法进行此调用,因此无法为我需要的数据obj加上额外的参数,因此有什么优雅的方法可以实现相同的效果(动态数据obj)?

任何提示将不胜感激。


Answers:


673

只需在prepareForSegue:method中获取对目标视图控制器的引用,然后将所需的任何对象传递到该对象即可。这是一个例子

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    // Make sure your segue name in storyboard is the same as this line
    if ([[segue identifier] isEqualToString:@"YOUR_SEGUE_NAME_HERE"])
    {
        // Get reference to the destination view controller
        YourViewController *vc = [segue destinationViewController];

        // Pass any objects to the view controller here, like...
        [vc setMyObjectHere:object];
    }
}

修订:您还可以使用performSegueWithIdentifier:sender:方法基于选择或按下按钮来激活到新视图的过渡。

例如,考虑我有两个视图控制器。第一个包含三个按钮,第二个需要知道在转换之前已按下了哪个按钮。您可以将按钮连接到IBAction使用performSegueWithIdentifier:方法的代码中的,例如...

// When any of my buttons are pressed, push the next view
- (IBAction)buttonPressed:(id)sender
{
    [self performSegueWithIdentifier:@"MySegue" sender:sender];
}

// This will get called too before the view appears
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:@"MySegue"]) {

        // Get destination view
        SecondView *vc = [segue destinationViewController];

        // Get button tag number (or do whatever you need to do here, based on your object
        NSInteger tagIndex = [(UIButton *)sender tag];

        // Pass the information to your destination view
        [vc setSelectedButton:tagIndex];
    }
}

编辑:我最初附加的演示应用程序现在已有6年的历史,因此为了避免混淆,我将其删除。


谢谢,但我想[vc setMyObjectHere:object];动态设置。即obj1表示button1,obj2表示button2。问题是我无法传递参数。有没有解决的办法?
chizzle

2
我已更新了我的帖子,并提供了可下载的示例。
西蒙(Simon)

起作用了!谢谢你 作为旁注,prepareForSegue:有一个UIControl自变量,它是UIButton的父类(因此可以获取标签):D
chizzle

即使您只是在没有情节提要segue的情况下推入导航控制器,是否也会调用prepareForSegue?
zakdances 2012年

这是我见过的最彻底的答案之一。好的代码示例,可以解决问题,提供可下载的示例...哇。给我留下深刻的印象!
lewiguez 2012年

82

有时,避免在两个视图控制器之间创建编译时依赖性很有帮助。在不关心目标视图控制器类型的情况下,可以按照以下方法进行操作:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.destinationViewController respondsToSelector:@selector(setMyData:)]) {
        [segue.destinationViewController performSelector:@selector(setMyData:) 
                                              withObject:myData];
    } 
}

因此,只要您的目标视图控制器声明了公共属性,例如:

@property (nonatomic, strong) MyData *myData;

您可以如上所述在先前的视图控制器中设置此属性。


12
这确实是一个见解的问题。我还没有遇到过“我不希望严格控制”视图控制器的情况,尽管我很欣赏您在说什么,在适当的情况下这很重要。
西蒙(Simon)

2
@Simon:是的,您只需选择最适合您的方法。例如,在我现在正在开发的应用程序中,我的方法很有意义,因为我一直在添加需要相同数据对象的视图控制器。能够仅通过segue挂接它们,并且知道它们将获取正确的数据非常方便。
Macondo2Seattle

10
这不是见仁见智,这是错误的:)“接受的答案不是做到这一点的最佳方法”这句话是错误的。它应显示为“在某些情况下,您需要执行此操作……”
Fattie 2014年

2
我喜欢西蒙的方法。因为它将告诉我编译时的错误。例如,如果我错过了目标视图控制器中myData的声明,我将立即知道。但是对于您的情况,您的方法似乎不错!
Abdurrahman Mubeen Ali 2014年

14
这种方法绝对会创建依赖项,因为您需要目标视图控制器具有setMyData:。那是一个依赖。使用选择器来避免编译错误的事实应视为方法的缺点,而不是好处。令我震惊的是,有许多开发人员已经失去了编译时错误应优先于运行时错误的概念。
Nate

21

在Swift 4.2中,我会做类似的事情:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if let yourVC = segue.destination as? YourViewController {
        yourVC.yourData = self.someData
    }
}

您是否需要致电:`super.prepare(for:segue,sender:sender)`?
安德鲁·K

16

我有一个发送者类,像这样

@class MyEntry;

@interface MySenderEntry : NSObject
@property (strong, nonatomic) MyEntry *entry;
@end

@implementation MySenderEntry
@end

我使用此发送器类将对象传递给prepareForSeque:sender:

-(void)didSelectItemAtIndexPath:(NSIndexPath*)indexPath
{
    MySenderEntry *sender = [MySenderEntry new];
    sender.entry = [_entries objectAtIndex:indexPath.row];
    [self performSegueWithIdentifier:SEGUE_IDENTIFIER_SHOW_ENTRY sender:sender];
}

-(void)prepareForSegue:(UIStoryboardSegue*)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:SEGUE_IDENTIFIER_SHOW_ENTRY]) {
        NSAssert([sender isKindOfClass:[MySenderEntry class]], @"MySenderEntry");
        MySenderEntry *senderEntry = (MySenderEntry*)sender;
        MyEntry *entry = senderEntry.entry;
        NSParameterAssert(entry);

        [segue destinationViewController].delegate = self;
        [segue destinationViewController].entry = entry;
        return;
    }

    if ([[segue identifier] isEqualToString:SEGUE_IDENTIFIER_HISTORY]) {
        // ...
        return;
    }

    if ([[segue identifier] isEqualToString:SEGUE_IDENTIFIER_FAVORITE]) {
        // ...
        return;
    }
}

在我们使用 prepareForSegue或我们正在实现它,假设是prepareForSegue被调用本身,即我们并不需要做类似的东西[self prepareForSegue]
蜂蜜

15

当我试图学习如何将数据从一个View Controller传递到另一个View Controller时遇到了这个问题。我需要视觉辅助来帮助我学习,因此,此答案是对此处已有答案的补充。它比原始问题更笼统,但可以适应工作。

这个基本示例如下所示:

在此处输入图片说明

想法是将字符串从“第一视图控制器”中的文本字段传递到“第二视图控制器”中的标签。

第一视图控制器

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
    }

}

记得

  • 通过使SEGUE control点击按钮,draging它移交给第二个视图控制器。
  • UITextField和的出口挂钩UILabel
  • 将第一个和第二个View Controller设置为IB中的相应Swift文件。

资源

如何通过Segue(Swift)发送数据(YouTube教程)

也可以看看

View Controllers:向前传递数据和向后传递数据(完整答案)


5

对于Swift来说,

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    var segueID = segue.identifier

    if(segueID! == "yourSegueName"){

        var yourVC:YourViewController = segue.destinationViewController as YourViewController

        yourVC.objectOnYourVC = setObjectValueHere!

    }
}

4

我在UIViewController上实现了带有类别的库,该库可简化此操作。基本上,您可以在与执行Segue的UI项相关联的NSDictionary中设置要传递的参数。它也适用于手动搜索。

例如,您可以

[self performSegueWithIdentifier:@"yourIdentifier" parameters:@{@"customParam1":customValue1, @"customValue2":customValue2}];

用于手动搜索或创建带有搜索的按钮并使用

[button setSegueParameters:@{@"customParam1":customValue1, @"customValue2":customValue2}];

如果目标视图控制器不符合键的键值编码,则不会发生任何事情。它也可以与键值一起使用(对于放松序列很有用)。在这里查看它 https://github.com/stefanomondino/SMQuickSegue


2

我的解决方案是相似的。

// In destination class: 
var AddressString:String = String()

// In segue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
   if (segue.identifier == "seguetobiddetailpagefromleadbidder")
    {
        let secondViewController = segue.destinationViewController as! BidDetailPage
        secondViewController.AddressString = pr.address as String
    }
}

1

只需使用此功能。

 override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    let index = CategorytableView.indexPathForSelectedRow
    let indexNumber = index?.row
    let VC = segue.destination as! DestinationViewController
   VC.value = self.data

}

0

我使用此解决方案是为了使segue的调用和数据通信保持在同一功能内:

private var segueCompletion : ((UIStoryboardSegue, Any?) -> Void)?

func performSegue(withIdentifier identifier: String, sender: Any?, completion: @escaping (UIStoryboardSegue, Any?) -> Void) {
    self.segueCompletion = completion;
    self.performSegue(withIdentifier: identifier, sender: sender);
    self.segueCompletion = nil
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    self.segueCompletion?(segue, sender)
}

用例将类似于:

func showData(id : Int){
    someService.loadSomeData(id: id) {
        data in
        self.performSegue(withIdentifier: "showData", sender: self) {
            storyboard, sender in
            let dataView = storyboard.destination as! DataView
            dataView.data = data
        }
    }
}

这似乎对我有用,但是,我不确定100%的执行和准备功能始终在同一线程上执行。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.