12

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

这完美地工作,但是我不能让它执行 unwind 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

有没有人成功地使用了结合视图控制器包含 API 的 unwind segues?知道我错过了哪一步吗?我已经将一个演示项目上传到 github,它在我能想到的最简单的演示项目中显示了这个问题。

4

4 回答 4

5

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

我有一个工作示例,表明它canPerformUnwindSegueAction确实在父链上进行了咨询,并且viewControllerForUnwindSegueAction如果segueForUnwindingToViewController出现在正确的位置,它就会被调用并且有效。看:

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

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

https://github.com/mattneub/UnwindSegues

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

于 2012-10-28T00:27:18.033 回答
2

Brief history before the answer: I just ran into the same exact error message when trying to use multiple Container Views on one iPad screen in iOS 6 and calling unwind segues from code. At first I thought this may be a problem because my segue was created using Storyboards by CTRL-dragging from File Owner to Exit instead of from some UI control to Exit, but I got same results when I put test Close buttons on each VC and had them trigger the unwind segues. I realized that I'm trying to unwind an embed segue, not a modal/push/popup segue, so it makes sense that it fails to do it. After all, if the unwind segue succeeds and the view controller is unloaded from a Container View, iOS 6 thinks there'll just be an empty space on the screen in that spot. (In my case, I have another container view taking up screen real estate that's shown behind the container view which I'm trying to unload, but iOS doesn't know that since the two aren't connected in any way.)

Answer: this led me to realize that you can only unwind modal, push, or popover segues, be it within the main window or as part of a Navigation/Tab Controller. This is b/c iOS then knows that there was a previous VC responsible for the whole screen and it's safe to go back to it. So, in your case, I'd look into a way to tell iOS that your child container view is connected to your parent container view in a way that makes it safe to dismiss the child container view. For example, perform a modal/push/popover segue when displaying the child container view, or wrap both into a custom UINavigationController class (I assume you don't want the navigation bar, that's why custom class).

Sorry I can't give exact code, but this is the best I got to so far and I hope it's helpful.

于 2013-02-06T14:01:38.263 回答
2

这似乎是一个错误——我也希望展开 segues 在你实现时工作。

我使用的解决方法是在 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];
          }
    }];
}
于 2012-10-17T09:52:30.993 回答
0

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

于 2016-01-29T12:39:09.053 回答