如何解除UIStoryboard中带有模态segue的模态?

Jaa*_*nus 32 cocoa-touch uistoryboard

设置:我有一个故事板设置,有两个简单的视图控制器A和B.A中有一个按钮,它转换为B模式segue.B在A之上呈现模态转换.没关系.

问题:有没有办法让B离开并用一些简单的故事板魔法回到A?

请注意,如果这一切都在导航控制器中,并且我使用了推送segue,那么它将被导航控制器隐含地处理.会有一个"后退"按钮.没有类似的模态,我需要自己构建UI,这很好,但我想知道是否有一个segue机制我可以用来发信号从B回到A.

现在构建从B到A的oldskool方法将是:

  • 在B上创建委托属性
  • 当模态转换segue回放时,将A设置为B的委托(我可以使用prepareForSegue挂钩:发件人:在A的代码中)
  • 当它被解雇时,B向其代表发出信号
  • A实现了一个解除B的委托方法

这可行,但感觉太多开销和愚蠢.

是否有一些我错过的UIStoryboard机制,基本上会做一个"反向模态segue"?

ric*_*ter 44

没有编写至少一点代码就没有任何故事板魔法来解雇模态视图控制器.

但是,虽然你必须实现自己的一些代码,但你不一定要遇到那么多麻烦.您可以在视图控制器B中调用一个按钮[self dismissViewControllerAnimated:YES completion:nil].(文档说,呈现视图控制器应该是解雇的,但他们也会说如果在出席者上调用,消息将被转发到呈现视图控制器.如果你想更明确地说明它 - 而且你'在某些情况下,例如当一个模态视图控制器出现在另一个模式视图控制器时 - 你可以明确地引用演示者self.presentingViewControllerdismiss...从那里调用.)

您在某些应用程序中看到委托业务,因为它是通知视图控制器A关于用户在视图控制器B中执行的操作的一种方式...但这不是唯一的方法.有KVO,通知,或只是简单地调用A的方法后参考它self.presentingViewController(假设B知道它总是由A呈现).如果A不需要知道B中发生的事情(例如,因为用户点击了取消按钮),则无需执行任何操作 - 您可以解雇该模式并完成它.


在iOS 6及更高版本中,展开segue添加了另一个选项,为解雇模态视图控制器(或以其他方式"退出"一系列segue)提供了一点"故事板魔术".但是这种方法仍然需要一些代码 - 你无法在故事板中完全设置它.但是,在正面,该代码提供了一个路径,用于从视图控制器中取消信息(B)到呈现它的信息(A).

Apple有一个关于展开细分的技术说明,详细介绍了它们,但这里是简短的版本:

  1. 定义IBAction你想放松视图控制器类的方法 -呈现一个模式视图控制器,而不是模式视图控制器本身(视图控制器A在你的问题)之一.与普通IBAction方法不同,这些方法应采用类型参数UIStoryboardSegue *; 例如

    - (IBAction)unwindToMainMenu:(UIStoryboardSegue*)sender
    
    Run Code Online (Sandbox Code Playgroud)
  2. 在显示的视图控制器(问题中的B)中,将控件连接到绿色的"退出"图标,然后选择您定义的方法.

  3. 在unwind方法实现中,您可以参考segue sourceViewController来从被解除的视图控制器中检索信息.您不需要调用dismissViewControllerAnimated:completion:因为segue处理解雇了正在消失的视图控制器.

  • 是的,如果你想进入自定义segue以便于重用,你可以做类似的事情 - (void)perform {UIViewController*src =(UIViewController*)self.sourceViewController; [src.presentingViewController dismissModalViewControllerAnimated:YES]; } (2认同)

Joh*_*rck 30

There is storyboard magic to achieve this. It's known as an unwind segue. In A's .h file you implement whatever "target action" style methods you need for however many unwind segues you need. For a modal, it's usually two (cancel and save). So in my A.h file I would add:

// A.h file
- (IBAction)myCancelUnwindSegueCallback:(UIStoryboardSegue *)segue;
- (IBAction)mySaveUnwindSegueCallback:(UIStoryboardSegue *)segue;
Run Code Online (Sandbox Code Playgroud)

Now, in your storyboard, if you have a segue from A to B. You can now do a "target action" style control drag from your cancel/save buttons in B to the green "Exit" icon at the bottom of the B controller in your storyboard. When you do this, Xcode will pick up the two methods we created (since they're in A's header file and they have the correct signature (e.g. IBAction and UIStoryboardSegue*.) and B is the destination of a segue from A) So, there you have it. You have the storyboard magic you were looking for!

In the implementation of the two callbacks, you would have something such as:

// A.m file
- (IBAction)myCancelUnwindSegueCallback:(UIStoryboardSegue *)segue {
    UIViewController *modalGoingAway = segue.sourceViewController;
    // Do something (like get data) from modalGoingAway if you need to...
}

- (IBAction)mySaveUnwindSegueCallback:(UIStoryboardSegue *)segue {
    UIViewController *modalGoingAway = segue.sourceViewController;
    // Do something (like get data) from modalGoingAway if you need to...
}
Run Code Online (Sandbox Code Playgroud)

Lastly, if this approach meets your needs, great. You're done. However, I still wire up the whole protocol delegate/dataSource design pattern if "on cancel" or "on save" I want to perform some operations on B's private properties before passing control over to A to remove B from the view hierarchy.