什么是Unwind segues,您如何使用它们?


584

iOS 6和Xcode 4.5具有称为“ Unwind Segue”的新功能:

放开序列可以允许过渡到情节提要中场景的现有实例

除了Xcode 4.5发行说明中的​​这一简短条目外,UIViewController现在似乎还有一些新方法:

- (BOOL)canPerformUnwindSegueAction:(SEL)action fromViewController:(UIViewController *)fromViewController withSender:(id)sender
- (UIViewController *)viewControllerForUnwindSegueAction:(SEL)action fromViewController:(UIViewController *)fromViewController withSender:(id)sender
- (UIStoryboardSegue *)segueForUnwindingToViewController:(UIViewController *)toViewController fromViewController:(UIViewController *)fromViewController identifier:(NSString *)identifier

放松搜寻如何工作,以及可以用来做什么?

Answers:


1267

简而言之

一个开卷赛格瑞(有时也被称为出口SEGUE)可用于通过推,模态或酥料饼塞格斯导航回(如,如果你从导航栏弹出导航项,关闭酥料饼或驳回模态呈现视图控制器)。最重要的是,您实际上不仅可以解开一个推入/模态/弹出窗口序列,而且可以通过单个解开动作“导航”导航层次结构中的多个步骤。

当执行展开搜索时,需要指定一个动作,这是您要展开到的视图控制器的动作方法。

目标C:

- (IBAction)unwindToThisViewController:(UIStoryboardSegue *)unwindSegue
{
}

迅速:

@IBAction func unwindToThisViewController(segue: UIStoryboardSegue) {
}

在情节提要中创建展开序列时,将使用此操作方法的名称。此外,此方法在执行展开搜索之前被调用。您可以从传递的UIStoryboardSegue参数中获取源视图控制器,以与启动segue的视图控制器进行交互(例如,获取模态视图控制器的属性值)。在这方面,该方法也有类似功能的prepareForSegue:方法UIViewController

iOS 8更新: Unwind segues也可以与iOS 8的自适应segues一起使用,例如ShowShow Detail

一个例子

让我们有一个带有导航控制器和三个子视图控制器的情节提要:

在此处输入图片说明

您可以从Green View Controller展开(向后导航)到Red View Controller。从蓝色,您可以展开为绿色或通过绿色为红色。要启用展开,必须将特殊的操作方法添加到红色和绿色中,例如,这是红色中的操作方法:

目标C:

@implementation RedViewController

- (IBAction)unwindToRed:(UIStoryboardSegue *)unwindSegue
{
}

@end

迅速:

@IBAction func unwindToRed(segue: UIStoryboardSegue) {
}

添加动作方法后,您可以通过按住Control键并拖动到“退出”图标来定义情节提要中的展开序列。在这里,我们想在按下按钮时从绿色退到红色:

在此处输入图片说明

您必须选择要在视图控制器中展开的动作:

在此处输入图片说明

您还可以从蓝色展开为红色(在导航堆栈中“相隔两步”)。关键是选择正确的展开动作。

在执行展开搜索之前,将调用action方法。在示例中,我定义了从绿色和蓝色到红色的展开顺序。我们可以通过UIStoryboardSegue参数在action方法中访问展开源:

目标C:

- (IBAction)unwindToRed:(UIStoryboardSegue *)unwindSegue
{
    UIViewController* sourceViewController = unwindSegue.sourceViewController;

    if ([sourceViewController isKindOfClass:[BlueViewController class]])
    {
        NSLog(@"Coming from BLUE!");
    }
    else if ([sourceViewController isKindOfClass:[GreenViewController class]])
    {
        NSLog(@"Coming from GREEN!");
    }
}

迅速:

@IBAction func unwindToRed(unwindSegue: UIStoryboardSegue) {
    if let blueViewController = unwindSegue.sourceViewController as? BlueViewController {
        println("Coming from BLUE")
    }
    else if let redViewController = unwindSegue.sourceViewController as? RedViewController {
        println("Coming from RED")
    }
}

放卷还可以通过组合推/模态搜索来完成。例如,如果我添加了另一个带有模态搜索的Yellow视图控制器,我们可以在一个步骤中从Yellow一直退回到Red:

在此处输入图片说明

从代码中解脱

通过控制将某些内容拖到视图控制器的“退出”符号上来定义展开序列时,新的序列会出现在“文档大纲”中:

在此处输入图片说明

选择segue并转到“属性”检查器,将显示“标识符”属性。使用它为您的segue提供唯一的标识符:

在此处输入图片说明

之后,可以像其他任何segue一样从代码中执行展开segue:

目标C:

[self performSegueWithIdentifier:@"UnwindToRedSegueID" sender:self];

迅速:

performSegueWithIdentifier("UnwindToRedSegueID", sender: self)

12
+1好答案。他们听起来很不错,但不能像方法dismissViewControllerAnimated:completion:popViewControllerAnimated:实现同样的事情?
Sam Spencer

32
当然可以。但是,如果您使用情节提要板,那么轻松的搜索通常可以用更少的代码来实现相同的目的。实际上,现在您无需编写任何代码就可以关闭模​​式呈现的视图控制器。当然,在很多情况下,从代码关闭控制器是正确的选择。
ImreKelényi13年

7
确保将操作方法​​添加到头文件中,否则情节提要不会知道。
Kyle C

17
相对于dismissViewControllerAnimated:completion:或的另一个优点popViewControllerAnimated:是,调用了添加到要解散的视图控制器的方法,因此您可以轻松地知道所呈现的视图控制器已完成,而不必使所呈现的视图控制器成为所呈现的视图控制器的委托。 。
hon13 2013年

8
我可以建议稍作修改吗?在RedViewController.m中放(IBAction)unwindTRed:(UIStoryboardSegue *)unwindSegue并不是很“明显”,然后可以在任何故事板上的“绿色”退出按钮中普遍使用。很棒的答案,现在我将其用于其他问题。谢谢!
约翰·巴林格

166

至于如何在StoryBoard中使用放开序列...

步骤1)

转到您想展开的视图控制器代码,并添加以下代码:

目标C

- (IBAction)unwindToViewControllerNameHere:(UIStoryboardSegue *)segue {
    //nothing goes here
}

确保还在Obj-C的.h文件中声明此方法

迅速

@IBAction func unwindToViewControllerNameHere(segue: UIStoryboardSegue) {
    //nothing goes here
}

第2步)

在情节提要中,转到您要放松的视图,只需将按钮或任何东西拖到源视图右上方的橙色小“ EXIT”图标上即可。

在此处输入图片说明

现在应该有一个选项可以连接到“-unwindToViewControllerNameHere”

就是这样,当您轻按按钮时,您的segue就会放松。


5
我发现在Xcode 4.5及更早版本中,有必要在标头中声明IBAction。我不知道这是否仍然正确。
史蒂芬·费舍尔

2
是否可以在没有情节提要的情况下(即以编程方式)执行第2步?我的情节提要(界面生成器)被弄乱了,并且没有显示放松的问题(xcode错误)。
Van Du Tran

46

展开segue用来“返回”某个视图控制器,通过一系列的segue,您可以从中获得“当前”视图控制器。

想象一下,您有一个MyNavControllerwith A作为其根视图控制器。现在,您可以对进行推送B。现在导航控制器的viewControllers数组中有A和B ,并且B是可见的。现在,您以C模态呈现。

有了解散键,您现在可以将“解回”从C到“退回” B(即关闭模态显示的视图控制器),基本上是“撤消”模态键。您甚至可以完全退回到根视图控制器A,同时撤消模态segue和push segue。

轻松进行搜寻可以轻松回溯。例如,在iOS 6之前,关闭展示的视图控制器的最佳实践是将展示的视图控制器设置为展示的视图控制器的委托,然后调用自定义委托方法,然后关闭presentedViewController。听起来麻烦又复杂?它是。这就是为什么放松的感觉很好。


7
您可以dismissViewController:animated从显示的控制器进行呼叫。您不必委托。当然,如果您需要传回数据,则需要委派或其他方法。
mxcl 2013年

3
dismissViewController:animated:正如您提到的,虽然可以从呈现的控制器中调用,但“最佳实践”确实是在呈现的控制器上调用委托方法来为您执行此操作。
克里斯·诺莱特

36

在其他答案中,我没有看到的是当您不知道初始序列的起源时如何处理展开,对我来说这是一个更重要的用例。例如,假设您有一个帮助视图控制器(H),可以从两个不同的视图控制器(AB)模态显示:

AH
BH

如何设置展开顺序,以便返回正确的视图控制器?答案是,您在AB 中用相同的名称声明一个展开动作,例如:

// put in AViewController.swift and BViewController.swift
@IBAction func unwindFromHelp(sender: UIStoryboardSegue) {
    // empty
}

这样,展开将找到哪个视图控制器(AB启动)并返回。

换句话说,将放松动作视为描述segue的来源,而不是去向。


2
感谢您提供此信息,我一直在寻找。
Madhu

2
提到此信息真的很棒,因为我已经在实施解决方案,在我向您提出建议之前什么都没有发生,非常感谢您的支持
Amr Angry

这是一个很棒的信息!非常感谢你!
Dominique Vial

24

Swift iOS:

步骤1:在您的MASTER控制器视图中定义此方法。您要返回的位置:

//pragma mark - Unwind Seques
@IBAction func goToSideMenu(segue: UIStoryboardSegue) {

    println("Called goToSideMenu: unwind action")

}

步骤2:(StoryBoard)右键单击SLAVE / CHILD EXIT按钮,然后选择“ goToSideMenu”作为“连接您”按钮的操作,您将单击该按钮以返回到主控制器视图:

在此处输入图片说明 步骤3:建立并执行...


1

例如,如果您从viewControllerB导航到viewControllerA,则在您的viewControllerA中,将调用委托并将共享数据。

@IBAction func unWindSeague (_ sender : UIStoryboardSegue) {
        if sender.source is ViewControllerB  {
            if let _ = sender.source as? ViewControllerB {
                self.textLabel.text = "Came from B = B->A , B exited"
            }
            
        }

}
  • 展开Seague Source View Controller(您需要将Exit Button连接到VC的退出图标,并将其连接到unwindseague:

在此处输入图片说明

  • 展开Seague已完成-> viewControllerA的TextLabel已更改。

在此处输入图片说明

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.