【问题标题】:Unwind segue to child view controllers not behaving as expected展开 segue 到子视图控制器的行为不符合预期
【发布时间】:2015-03-10 13:35:19
【问题描述】:

当与模态视图和容器视图结合使用时,在 iOS 8.1 中展开转场的行为似乎不如预期。 这是测试项目的视图控制器层次结构,可以是found on github

点击“点击我”按钮会推动嵌入在导航控制器中的模态视图,该视图将 tableView 作为子视图控制器。点击 tableView 中的一行会推送另一个 tableView。最后,点击最终 tableView 中的一行应该调用在前一个视图控制器上找到的名为 bUnwindSegue 的展开 segue。

问题:

  1. bUnwindSegue 永远不会被调用。
  2. 根据技术说明TN2298,容器视图控制器负责选择子视图控制器来处理segue。在这种情况下,应该在容器视图控制器上调用 viewControllerForUnwindSegueAction:fromViewController:withSender:。不是。

在示例项目中,您可以看到BTableViewController 包含展开转场:

- (IBAction)bUnwindSegue:(UIStoryboardSegue *)segue;
{
    NSLog(@"Unwinding...this unwind segue will never get called.");
}

在情节提要中,CTableViewController 的单元格选择操作确实是bUnwindSegue。另请注意,如果您将CTableViewController 的单元格选择操作更改为容器视图控制器中的展开转场 -- containerVCUnwindSegue -- 则转场被正确调用。

unwind segues 的行为是否不符合预期?

【问题讨论】:

  • 你的展开segue方法应该在你正在展开的视图控制器中。
  • @LyndseyScott BTableViewController 是正在解压到的 VC。
  • @LyndseyScott 展开转场目前是通过情节提要设置的。那里也需要发生变化。或者,您可以删除情节提要展开并以编程方式设置它。我希望这两种情况的行为相同。
  • 刚刚意识到我误读了我引用的第二句话......而且我通常把 B C 和 TableViewControllers 搞混了......不过我现在已经赶上了并重新考虑......
  • 除非您将 segue 放入容器视图控制器中,否则它不会转换回来的原因是因为与 CTableViewController 不同,BTableViewController 并未作为独立视图控制器添加到堆栈中,而是作为您的容器容器视图控制器。

标签: ios uistoryboardsegue ios8.1 uicontainerview unwind-segue


【解决方案1】:

(1) 您误解了您引用的技术说明 TN2298,并且 (2) 您没有适当地覆盖 viewControllerForUnwindSegueAction:

正如您链接到的关于容器视图控制器的 TN2298 文档部分在其“选择子视图控制器以处理展开操作”子标题下声明:

您的容器视图控制器应覆盖中显示的方法 [viewControllerForUnwindSegueAction:] 搜索其子项 想要处理展开的视图控制器的视图控制器 行动。如果容器的子视图控制器都不想处理 展开动作,它应该调用超级的实现并返回 结果。

首先,要覆盖该方法,您必须在情节提要中继承 UINavigationController 并在其中添加 viewControllerForUnwindSegueAction: 方法。完成此操作后,您将看到该方法现在正在按预期调用。

但是您的第二个错误是您当前尝试覆盖viewControllerForUnwindSegueAction: 方法只包含return self;。相反,您应该返回要处理展开操作的视图控制器。

假设,例如,您在 VCWithContainedVCsViewController 中有一个公共变量来保存 BTableViewController 的当前实例,并且您可以访问该当前容器视图控制器,例如:

- (UIViewController *)viewControllerForUnwindSegueAction:(SEL)action fromViewController:(UIViewController *)fromViewController withSender:(id)sender
{
    NSLog(@"Technical note TN2298 indicates child VCs defer to their parent to determine where an unwind segue will be handled.");

    if ([NSStringFromSelector(action) isEqualToString:@"bUnwindSegue:"]) {

        NSLog(@"%@", self.viewControllers);
        VCWithContainedVCsViewController *containerVC = (VCWithContainedVCsViewController*)self.viewControllers[0];
        return containerVC.container;
    }

    return [super viewControllerForUnwindSegueAction:action fromViewController:fromViewController withSender:sender];
}

在这种情况下,您会看到 bUnwindSegue: 实际上被调用(您的消息应该打印出来),但转场仍然不会发生。

这是为什么?

因为正如我在 cmets 中提到的,BTableViewController 在当前导航堆栈中不是BTableViewController 的一些子视图控制器,如 CTableViewController,将位于导航堆栈上,因为例如,CTableViewController 不是容器视图。但是BTableViewController 本身无法自行执行 segue,因为它不在当前导航堆栈上。因此,尽管您实际上可以选择一些子视图控制器来处理文档所述的展开操作,但 BTableViewController 不会是其中之一。

【讨论】:

  • 你误解了正在发生的事情 - VCWithContainedVCsViewController 上的 viewControllerForUnwindSegueAction 永远不会被调用。我将 self 作为存根返回并在那里放置一个断点以进行测试。
  • @MichaelG.Emmons 我没有误会。就像我说的那样,它没有被调用,因为它不应该在您的视图控制器的类中,而是在您的导航视图控制器的子类中:“首先,要覆盖该方法,您必须在情节提要中继承 UINavigationController 并添加 viewControllerForUnwindSegueAction : 方法。完成之后,您会看到该方法现在正在按预期调用。"
  • 啊。我看到这个 SO 答案还建议子类化导航控制器(stackoverflow.com/questions/16092189/…)。很公平,但这与技术说明所表明的直接相反,If you are using the container view controllers provided by the SDK, such as UINavigationController, these are handled automatically.
  • @MichaelG.Emmons 不,技术说明是正确的。您的导航控制器正在尝试按预期自动展开 - 只是(就像我在评论中和回答末尾所说的那样)BTableViewController 实际上不在导航堆栈上,因此它无法执行放松。通过使用viewControllerForUnwindSegueAction: 覆盖 UINavigation 控制器的自动操作并强制BTableViewController 中执行即使消息打印,您仍然会看到没有任何反应。
  • @MichaelG.Emmons 另请注意,由于BTableViewController 无法执行展开,UINavigationController(如果viewControllerForUnwindSegueAction: 未被覆盖)将继续向下查看导航堆栈,因此如果你把bUnwindSegue:放在容器VC中它应该被执行。 (无需像在当前代码中进行测试那样创建不同的 segue。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-05
  • 2015-06-22
  • 1970-01-01
  • 2020-05-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多