使用自定义视图控制器包含时无法创建展开segue

时间:2012-09-30 22:49:48

标签: cocoa-touch uistoryboard uistoryboardsegue

我正在尝试将我们的应用程序转换为故事板,并且在处理自定义容器控制器时遇到了我认为处理展开segue的错误。我们有一个视图控制器,它显示另一个并使用视图控制器包含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];
                    }];
}

完美无缺,但我不能让它执行展开segue回到容器控制器。我重写了viewControllerForUnwindSegueAction:fromViewController:withSender:并确保它返回正确的值:

-(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:要调用,但它永远不会。相反,应用程序崩溃时出现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

有没有人成功使用unwind segue和视图控制器包含API?知道我错过了哪一步?我上传了一个demo project to github,在我能提出的最简单的示范项目中显示了这个问题。

4 个答案:

答案 0 :(得分:5)

你的例子中的问题是那里没有。它很简单。首先,您以一种相当奇怪的方式创建容器视图控制器(您不使用新的IB“容器视图”来帮助您执行此操作)。其次,你没有什么可以放松的:没有任何东西被推到或呈现在任何东西之上。

我有一个工作示例,表明canPerformUnwindSegueAction确实被咨询了父链,viewControllerForUnwindSegueActionsegueForUnwindingToViewController被调用并且有效,如果它出现在正确的位置。参见:

https://github.com/mattneub/Programming-iOS-Book-Examples/tree/master/ch19p640presentedViewControllerStoryboard2

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

https://github.com/mattneub/UnwindSegues

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

答案 1 :(得分:2)

这似乎是一个错误 - 我也希望在你实施的时候解开细分。

我使用的解决方法是明确地忽略IBAction方法中提供的视图控制器:

- (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];
          }
    }];
}

答案 2 :(得分:2)

回答之前的简史:我尝试在iOS 6的一个iPad屏幕上使用多个容器视图并从代码中调用展开segues时遇到了同样的错误消息。起初我认为这可能是一个问题,因为我的segue是使用Storyboard通过CTRL从文件所有者拖动到Exit而不是从某个UI控件创建到Exit,但是当我在每个VC上放置测试关闭按钮时我得到了相同的结果它们会触发展开的细分。我意识到我正在试图解开嵌入segue,而不是modal / push / popup segue,所以它没有做到这一点是有意义的。毕竟,如果unwind segue成功并且视图控制器从Container View中卸载,iOS 6认为屏幕上只有一个空白区域。 (在我的情况下,我有另一个容器视图占用屏幕空间,显示在容器视图后面,我正在尝试卸载,但iOS不知道,因为这两者没有以任何方式连接。)

答案:这让我意识到你只能在主窗口内或作为导航/标签控制器的一部分展开模态,推送或弹出窗口。这是b / c iOS然后知道有一个以前的VC负责整个屏幕,回到它是安全的。因此,在您的情况下,我会研究一种方法来告诉iOS您的子容器视图以一种可以安全地关闭子容器视图的方式连接到您的父容器视图。例如,在显示子容器视图时执行modal / push / popover segue,或将两者都包装到自定义UINavigationController类中(我假设您不需要导航栏,这就是自定义类的原因)。

抱歉,我无法提供确切的代码,但这是我到目前为止所做的最好的,我希望它有用。

答案 3 :(得分:0)

在iOS9中看起来已修复此错误。