Cocoa touch 使用自定义视图控制器包含时无法创建展开分段

Cocoa touch 使用自定义视图控制器包含时无法创建展开分段,cocoa-touch,uistoryboard,uistoryboardsegue,Cocoa Touch,Uistoryboard,Uistoryboardsegue,我正在尝试将我们的应用程序转换为故事板,并且在处理自定义容器控制器时遇到了一个我认为在处理展开分段时存在的错误。我们有一个视图控制器,它显示另一个视图控制器,并使用视图控制器包含api来实现这一点,我在IB中连接segue,然后为实现选择一个自定义类。perform方法如下所示: -(void) perform { UIViewController *container = [self sourceViewController]; UIViewController *child

我正在尝试将我们的应用程序转换为故事板,并且在处理自定义容器控制器时遇到了一个我认为在处理展开分段时存在的错误。我们有一个视图控制器,它显示另一个视图控制器,并使用视图控制器包含api来实现这一点,我在IB中连接segue,然后为实现选择一个自定义类。perform方法如下所示:

-(void) perform {
    UIViewController *container = [self sourceViewController];
    UIViewController *child = [self destinationViewController];
    [container addChildViewController:child];
    [container.view addSubview:child.view];
    child.view.center = container.view.center;
    [UIView transitionWithView:container.view
                      duration:0.35
                       options:UIViewAnimationOptionCurveEaseInOut
                    animations:^{
                        child.view.alpha = 1;
                    } completion:^(BOOL finished) {
                        [child didMoveToParentViewController:container];
                    }];
}
这工作得很好,但是我不能让它执行到容器控制器的展开过程。我使用Sender:覆盖viewControllerForUnwindSegueAction:fromViewController:并确保返回正确的值:

-(UIViewController *) viewControllerForUnwindSegueAction:(SEL)action fromViewController:(UIViewController *)fromViewController withSender:(id)sender {
    id default = [super viewControllerForUnwindSegueAction:action fromViewController:fromViewController withSender:sender];
    NSAssert1(default == self, @"Expected the default view controller to be self but was %@", default);
    return default;
}
我还可以确认canPerformUnwindSegueAction:fromViewController:withSender正在被调用,并且正在做正确的事情,但为了确保我覆盖了它以返回YES

-(BOOL) canPerformUnwindSegueAction:(SEL)action fromViewController:(UIViewController *)fromViewController withSender:(id)sender {
    return YES;
}
我希望发生的下一步是调用segueForUnwindingToViewController:fromViewController:identifier:segueForUnwindingToViewController,但它永远不会被调用。相反,应用程序会因NSInternalInconsistencyException而崩溃

2012-10-01 10:56:33.627 UnwindSegues[12770:c07] *** Assertion failure in -[UIStoryboardUnwindSegueTemplate _perform:], /SourceCache/UIKit_Sim/UIKit-2372/UIStoryboardUnwindSegueTemplate.m:78
2012-10-01 10:56:33.628 UnwindSegues[12770:c07] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Could not find a view controller to execute unwinding for <USCustomContainerViewController: 0x75949a0>'
*** First throw call stack:
(0x1c8e012 0x10cbe7e 0x1c8de78 0xb61f35 0x581711 0x45ab54 0x10df705 0x16920 0x168b8 0xd7671 0xd7bcf 0xd6d38 0x4633f 0x46552 0x243aa 0x15cf8 0x1be9df9 0x1be9ad0 0x1c03bf5 0x1c03962 0x1c34bb6 0x1c33f44 0x1c33e1b 0x1be87e3 0x1be8668 0x1365c 0x1e7d 0x1da5)
libc++abi.dylib: terminate called throwing an exception
2012-10-01 10:56:33.627解绑分段[12770:c07]***在-[UIStoryboardUnwindSegueTemplate\u-perform:],/SourceCache/UIKit\u-Sim/UIKit-2372/UIStoryBoardUndWindSegueTemplate.m:78中断言失败
2012-10-01 10:56:33.628解绑段[12770:c07]***由于未捕获的异常“NSInternalInconsistenceException”而终止应用程序,原因是:“找不到要为其执行解绑的视图控制器”
***第一次抛出调用堆栈:
(0x1c8e012 0x10cbe7e 0x1c8de78 0xb61f35 0x581711 0x45ab54 0x10df705 0x16920 0x168b8 0xd7671 0xd7bcf 0xd6d38 0x4633f 0x46552 0x243aa 0x15cf8 0x1be9df9 0x1be9ad0 0x1c03bf5 0x1c03962 0x1c34bb6 0x1c33f44 0x1c33e1b 0x1be87e3 0x1be8668 0x1365c 0x1e7d 0x1da5)
libc++abi.dylib:terminate调用引发异常

是否有人成功地使用了与视图控制器包含API相结合的展开分段?知道我错过了哪一步吗?我上传了一篇文章,在我能想到的最简单的演示项目中展示了这个问题。

这似乎是一个bug–我还希望在您实现的过程中,展开段也能正常工作

我使用的解决方法是在iAction方法中明确取消显示的视图控制器:

- (UIStoryboardSegue *)segueForUnwindingToViewController:(UIViewController *)toViewController
                                      fromViewController:(UIViewController *)fromViewController
                                              identifier:(NSString *)identifier
{
    return [[UIStoryboardSegue alloc] initWithIdentifier:identifier
                                                 source:fromViewController
                                             destination:toViewController];
}

- (IBAction)unwind:(UIStoryboardSegue*)segue
{
    UIViewController *vc = segue.sourceViewController;
    [vc willMoveToParentViewController:nil];
    if ([vc respondsToSelector:@selector(beginAppearanceTransition:animated:)]) {
        [vc beginAppearanceTransition:NO animated:YES]; // iOS 6
    }
    UIView *modal = vc.view;
    UIView *target = [[segue destinationViewController] view];
    [UIView animateWithDuration:duration animations:^{
        modal.frame = CGRectMake(0, target.bounds.size.height, modal.frame.size.width, modal.frame.size.height);
     } completion:^(BOOL finished) {
        [modal removeFromSuperview];
        [vc removeFromParentViewController];
        if ([vc respondsToSelector:@selector(endAppearanceTransition)]) {
            [vc endAppearanceTransition];
          }
    }];
}

你的例子中的问题是那里没有。太简单了。首先,您以一种非常奇怪的方式创建容器视图控制器(您没有使用新的IB“容器视图”,它可以帮助您完成这项工作)。其次,你没有什么可以放松的:没有任何东西被推到或呈现在任何东西之上

我有一个工作示例显示,
canPerformUnwindSegueAction
确实是在父链上进行查询的,如果在正确的位置出现,
viewControllerForUnwindSegueAction
segueForUnwindingToViewController
被调用且有效。见:

现在,我还在github上创建了一个原始示例的分支,并对其进行了更正,以说明以下功能:


这并不是真正需要“展开”的情况,但它确实显示了在涉及自定义容器视图控制器时如何使用“展开”。

回答之前的简要历史:在iOS 6中尝试在一个iPad屏幕上使用多个容器视图并从代码中调用展开分段时,我遇到了相同的错误消息。起初,我认为这可能是一个问题,因为我的segue是使用故事板创建的,通过CTRL键从文件所有者拖动到退出,而不是从一些UI控件拖动到退出,但当我在每个VC上放置测试关闭按钮并让它们触发展开segue时,我得到了相同的结果。我意识到我正在尝试解开一个嵌入序列,而不是一个模式/推送/弹出序列,所以它失败是有道理的。毕竟,如果展开成功,并且视图控制器从容器视图中卸载,iOS 6认为屏幕上该位置将只有一个空白。(在我的例子中,我有另一个占据屏幕空间的容器视图,它显示在我试图卸载的容器视图后面,但iOS不知道,因为两者没有任何连接。)

答:这让我意识到,无论是在主窗口内还是作为导航/选项卡控制器的一部分,您都只能释放模态、推送或弹出序列。这是b/c,iOS知道之前有一个VC负责整个屏幕,可以安全地返回。因此,在您的情况下,我将研究一种方法,告诉iOS您的子容器视图已连接到父容器视图,这样可以安全地关闭子容器视图。例如,在显示子容器视图时执行模态/push/popover序列,或者将两者包装到自定义UINavigationController类中(我假设您不需要导航栏,这就是自定义类的原因)


很抱歉,我无法给出确切的代码,但这是我迄今为止得到的最好的代码,我希望它能有所帮助。

这个错误似乎在iOS9中得到了修复。

供参考:我想我应该尝试编辑它,但由于编辑少于6个字符,所以不允许我使用链接。链接已死亡:(@lostintranslation)答案(和链接)它们现在已经毫无意义了,因为放松片段现在的工作方式与当时完全不同。@lostintranslation这可能是我的保留曲目中最接近的东西:这应该是注释。