在我的viewDidAppear中,我如何知道孩子什么时候被解开?

当我的孩子执行展开segue时,我的控制器的viewDidAppear被调用。

在这种方法中(仅此方法,我需要知道它是否来自放松)

注意:子节点正在向第一个视图控制器展开,因此这是一个中间视图控制器,而不是真正的根节点。

您应该能够使用以下内容在每个控制器中检测视图控制器的曝光是由于被推/呈现的结果,还是由于弹出/解除/展开而暴露的结果。

这可能或可能足以满足您的需求。

 - (void) viewDidAppear:(BOOL)animated{ [super viewDidAppear:animated]; // Handle controller being exposed from push/present or pop/dismiss if (self.isMovingToParentViewController || self.isBeingPresented){ // Controller is being pushed on or presented. } else{ // Controller is being shown as result of pop/dismiss/unwind. } } 

如果你想知道viewDidAppear被调用是因为unwind segue与传统的pop / dismiss被调用不同,那么你需要添加一些代码来检测是否发生了展开。 为此,您可以执行以下操作:

对于您想要纯粹检测的任何中间控制器,添加表单的属性:

 /** BOOL property which when TRUE indicates an unwind occured. */ @property BOOL unwindSeguePerformed; 

然后重写unwind segue方法canPerformUnwindSegueAction:fromViewController:withSender:方法如下:

 - (BOOL)canPerformUnwindSegueAction:(SEL)action fromViewController:(UIViewController *)fromViewController withSender:(id)sender{ // Set the flag indicating an unwind segue was requested and then return // that we are not interested in performing the unwind action. self.unwindSeguePerformed = TRUE; // We are not interested in performing it, so return NO. The system will // then continue to look backwards through the view controllers for the // controller that will handle it. return NO; } 

现在你有一个标志来检测一个展开,以及一个在它发生之前检测展开的方法。 然后调整viewDidAppear方法以包含此标志。

 - (void) viewDidAppear:(BOOL)animated{ [super viewDidAppear:animated]; // Handle controller being exposed from push/present or pop/dismiss // or an unwind if (self.isMovingToParentViewController || self.isBeingPresented){ // Controller is being pushed on or presented. // Initialize the unwind segue tracking flag. self.unwindSeguePerformed = FALSE; } else if (self.unwindSeguePerformed){ // Controller is being shown as a result of an unwind segue } else{ // Controller is being shown as result of pop/dismiss. } } 

希望这符合您的要求。

有关处理展开segue链的文档,请参阅: https : //developer.apple.com/library/ios/technotes/tn2298/_index.html

这是UIViewController上的一个简单类别,您可以使用它来跟踪您呈现的视图控制器是否处于展开segue中。 我想它可能会更多,但我相信这对你的情况很有用。

要使用它,您需要在目标视图控制器上注册unwind操作方法中的展开segue:

 - (IBAction) prepareForUnwind:(UIStoryboardSegue *)segue { [self ts_registerUnwindSegue: segue]; } 

而已。 从中间视图控制器,您可以测试您是否处于展开segue中:

 - (void) viewDidAppear:(BOOL)animated { [super viewDidAppear: animated]; BOOL unwinding = [self ts_isUnwinding]; NSLog( @"%@:%@, unwinding: %@", self.title, NSStringFromSelector(_cmd), unwinding ? @"YES" : @"NO" ); } 

没有必要清理任何东西; segue会在结束时自行注销。

这是完整的类别:

 @interface UIViewController (unwinding) - (void) ts_registerUnwindSegue: (UIStoryboardSegue*) segue; - (BOOL) ts_isUnwinding; @end static NSMapTable* g_viewControllerSegues; @implementation UIViewController (unwinding) - (void) ts_registerUnwindSegue: (UIStoryboardSegue*) segue { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ g_viewControllerSegues = [NSMapTable weakToWeakObjectsMapTable]; }); for ( UIViewController* vc = segue.sourceViewController ; vc != nil ; vc = vc.presentingViewController ) { [g_viewControllerSegues setObject: segue forKey: vc]; } } - (BOOL) ts_isUnwinding { return [g_viewControllerSegues objectForKey: [self ts_topMostParentViewController]] != nil; } - (UIViewController *)ts_topMostParentViewController { UIViewController *viewController = self; while (viewController.parentViewController) { viewController = viewController.parentViewController; } return viewController; } @end 

你的问题对我来说真的很有意思,因为我之前从未使用过IB和segues(不要为此判断我)并且想学习一些新东西。 正如您在评论中所描述的那样:

C退到A时,将在B上调用viewDidAppear

所以我想出了一个简单的自定义解决方案:

 protocol ViewControllerSingletonDelegate: class { func viewControllerWillUnwind(viewcontroller: UIViewController, toViewController: UIViewController) } class ViewControllerSingleton { static let sharedInstance = ViewControllerSingleton() private var delegates: [ViewControllerSingletonDelegate] = [] func addDelegate(delegate: ViewControllerSingletonDelegate) { if !self.containsDelegate(delegate) { self.delegates.append(delegate) } } func removeDelegate(delegate: ViewControllerSingletonDelegate) { /* implement any other function by your self :) */ } func containsDelegate(delegate: ViewControllerSingletonDelegate) -> Bool { for aDelegate in self.delegates { if aDelegate === delegate { return true } } return false } func forwardToDelegate(closure: (delegate: ViewControllerSingletonDelegate) -> Void) { for aDelegate in self.delegates { closure(delegate: aDelegate) } } } class SomeViewController: UIViewController, ViewControllerSingletonDelegate { let viewControllerSingleton = ViewControllerSingleton.sharedInstance func someFunction() { // some function where you'll set the delegate self.viewControllerSingleton.addDelegate(self) } /* I assume you have something like this in your code */ @IBAction func unwindToSomeOtherController(unwindSegue: UIStoryboardSegue) { self.viewControllerSingleton.forwardToDelegate { (delegate) -> Void in delegate.viewControllerWillUnwind(unwindSegue.sourceViewController, toViewController: unwindSegue.destinationViewController) } /* do something here */ } // MARK: - ViewControllerSingletonDelegate func viewControllerWillUnwind(viewcontroller: UIViewController, toViewController: UIViewController) { /* do something with the callback */ /* set some flag for example inside your view controller so your viewDidAppear will know what to do */ } } 

您还可以修改回调函数以返回其他内容,例如控制器标识符,而不是控制器本身。

我以编程方式完成所有工作,所以请不要因此而对我进行评判。 ;)

如果此代码段对您没有帮助,我仍然希望看到一些反馈。

假设segue导航是ViewController – > FirstViewController – > SecondViewController。 从SecondViewControllerViewController有一个放松。 您可以在中间FirstViewController添加以下代码来检测展开操作。

 import UIKit class FirstViewController: UIViewController { var unwindAction:Bool = false override func viewDidAppear(animated: Bool) { if unwindAction { println("Unwind action") unwindAction = false } } override func viewControllerForUnwindSegueAction(action: Selector, fromViewController: UIViewController, withSender sender: AnyObject?) -> UIViewController? { self.unwindAction = true return super.viewControllerForUnwindSegueAction(action, fromViewController: fromViewController, withSender: sender) } } 

编辑在考虑了这个问题之后,我决定解决这个问题取决于你在这里处理的复杂程度。 当您放松时,您到底做了什么? 这里给出的解决方案是可行的,它们可以工作 – 只有当你想要检测它是否是一个展开动作时。 如果要在展开的点到根之间传递数据,该怎么办? 如果您想在其中一个中间视图控制器中进行一系列复杂的准备工作,该怎么办? 如果你想做这两件事怎么办?

在这种复杂的场景中,我会立即排除覆盖视图控制器的展开方法。 做这样的操作会有效,但不会很干净。 一种方法将做它不应该做的事情。 闻到了吗? 那是代码味道。

如果某个视图控制器可以在事件发生的层次结构中通知下一个视图控制器怎么办? 更好的是,我们如何在不紧密耦合这两者的情况下做到这一点?

协议。

有一个协议定义类似于:

 protocol UnwindResponding { prepareForUnwindSegue(segue:UISegue , formViewController:UIViewController, withImportantInfo info:[String,AnyObject]) } 

使用协议,您将保持对象之间的关系 – 在这种情况下视图控制器的层次结构 – 显式。 在发生特定事件时,您将调用委托给层次结构中的下一个控制器,以通知另一个视图控制器中特定事件的发生。 这是一个例子:

 override func prepareForSegue(segue:UIStoryboardSegue, sender:AnyObject?) { if let unwindResponder = self.presentingViewController as? UnwindResponding where segue.identifier = "unwindSegue" { unwindResponder.prepareForUnwindSegue(segue:UISegue, fromViewController:self,info:info) } } 

在中间视图控制器中,您可以执行以下操作:

 extension IntermediaryViewController : UnwindResponding { prepareForUnwindSegue(segue:UISegue , fromViewController:UIViewController, withImportantInfo info:[String,AnyObject]) { if let unwindResponder = self.presentingViewController { unwindResponder.prepareForUnwindSegue(segue,fromViewController:fromViewController, info:info) } unwindSegue = true } } 

当然,如果您只是想要检测放松细分,您不会想要这样做。 也许你这样做,你永远不会知道将来会发生什么。 永远不要伤害你的代码清洁。

在父视图控制器中添加方法

 @IBAction func unwindToParent(unwindSegue: UIStoryboardSegue) { if let childViewController = unwindSegue.sourceViewController as? ChildViewController { println("unwinding from child") } } 

作为示例,如果展开segue与按钮相关,则在故事板链接中将按钮链接到其视图控制器出口

在此处输入图像描述

它将建议链接到unwindToParent方法

在此处输入图像描述

然后每次执行展开segue时,都会调用unwindToParent方法

对于其他任何寻找这个的人,在swift中你可以使用覆盖函数“unwind”,当ViewController在unwind segue的路径上时调用它,意味着重新配置ViewController。

例:

 override func unwind(for unwindSegue: UIStoryboardSegue, towardsViewController subsequentVC: UIViewController) { }