【问题标题】:How to pass prepareForSegue: an object如何通过prepareForSegue:一个对象
【发布时间】:2011-12-13 10:38:20
【问题描述】:

我在地图视图中有很多注释(带有rightCalloutAccessory 按钮)。该按钮将执行从mapviewtableview 的转换。我想将 tableview 传递给不同的对象(包含数据),具体取决于单击了哪个标注按钮。

例如:(完全虚构)

  • annotation1 (Austin) -> 传递数据 obj 1(与 Austin 相关)
  • annotation2(达拉斯)-> 传递数据 obj 2(与达拉斯有关)
  • annotation3 (Houston) -> 传递数据 obj 3 等等...(你得到 想法)

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

我正在使用 prepareForSegue: 将数据 obj 传递到目标 ViewController。由于我不能让这个调用为我需要的数据 obj 提供额外的参数,有哪些优雅的方法可以实现相同的效果(动态数据 obj)?

任何提示将不胜感激。

【问题讨论】:

标签: ios xcode uitableview mapkit storyboard


【解决方案1】:

只需在prepareForSegue: 方法中获取对目标视图控制器的引用,并将您需要的任何对象传递到那里。这是一个例子......

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

REVISION:您还可以使用performSegueWithIdentifier:sender: 方法根据选择或按钮按下来激活到新视图的转换。

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

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

编辑:我最初附加的演示应用程序现在已经使用了六年,因此我将其删除以避免任何混淆。

【讨论】:

  • 谢谢,但我想动态设置[vc setMyObjectHere:object];。即按钮1的obj1,按钮2的obj2问题是我无法传递参数。有没有办法解决这个问题?
  • 我已经更新了我的帖子,并提供了一个可下载的示例。
  • 成功了!谢谢一堆。作为旁注 prepareForSegue: 有一个 UIControl 参数,它是 UIButton 的父类(因此能够获取标签):D
  • 即使您只是在没有故事板 segue 的情况下推送到导航控制器,prepareForSegue 是否也会被调用?
  • 这是我见过的最彻底的答案之一。好的代码示例,解决了问题,提供了可下载的示例......哇。我印象深刻!
【解决方案2】:

有时避免在两个视图控制器之间创建编译时依赖关系是有帮助的。以下是您可以在不关心目标视图控制器类型的情况下执行此操作的方法:

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

你可以像我上面描述的那样在之前的视图控制器中设置这个属性。

【讨论】:

  • 这真是见仁见智。我(还)没有遇到过不想“严格”控制视图控制器的情况,尽管我很欣赏您所说的话,并且在适当的情况下这可能很重要。
  • @Simon:是的,您只需选择最适合您的方法。例如,在我现在正在开发的应用程序中,我的方法很有意义,因为我不断添加需要相同数据对象的视图控制器。只需一个 segue 就能将它们连接起来,并且知道它们将获得正确的数据,这非常方便。
  • 这不是意见问题,只是错误的 :) 短语“接受的答案不是这样做的最佳方式”是错误的。它应该是“在某些情况下,你需要这样做……”
  • 我更喜欢西蒙的方法。因为它会在编译时告诉我错误。例如,如果我错过了目标视图控制器中 myData 的声明,我会立即知道。但是对于您的场景,您的方法似乎不错!
  • 这种方法确实会产生依赖,因为您需要目标视图控制器具有setMyData:。那是一种依赖。您使用选择器来避免编译错误这一事实应被视为您方法的弱点,而不是好处。令我震惊的是,有多少开发人员已经失去了编译时错误应该优先于运行时错误的概念。
【解决方案3】:

在 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)`?
【解决方案4】:

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

@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]
【解决方案5】:

当我试图学习如何将数据从一个视图控制器传递到另一个视图控制器时,我遇到了这个问题。我需要一些视觉上的东西来帮助我学习,所以这个答案是对已经在这里的其他答案的补充。它比原始问题更笼统,但可以适应工作。

这个基本的例子是这样工作的:

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

第一个视图控制器

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
    }

}

记得

  • 通过control点击按钮并将其拖到第二个视图控制器上来制作segue。
  • 连接UITextFieldUILabel 的插座。
  • 将第一个和第二个视图控制器设置为 IB 中的相应 Swift 文件。

来源

How to send data through segue (swift)(YouTube 教程)

另见

View Controllers: Passing data forward and passing data back(更完整的答案)

【讨论】:

    【解决方案6】:

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

    【讨论】:

      【解决方案7】:

      我在 UIViewController 上实现了一个类库,简化了这个操作。 基本上,您在与执行 segue 的 UI 项关联的 NSDictionary 中设置要传递的参数。它也适用于手动转场。

      例如,你可以这样做

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

      用于手动转场或使用转场创建按钮并使用

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

      如果目标视图控制器不符合键的键值编码,则不会发生任何事情。它也适用于键值(对于展开 segues 很有用)。 在这里查看 https://github.com/stefanomondino/SMQuickSegue

      【讨论】:

        【解决方案8】:

        我的解决方案类似。

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

        【讨论】:

          【解决方案9】:

          只需使用此功能。

           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
          
          }
          

          【讨论】:

            【解决方案10】:

            我使用了这个解决方案,以便我可以将 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% 确定 perform 和 prepare 函数总是在同一个线程上执行。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2023-04-04
              • 1970-01-01
              • 2020-01-27
              • 2021-10-30
              • 1970-01-01
              • 1970-01-01
              • 2017-12-21
              相关资源
              最近更新 更多