Unwind segue 在非模态时不会关闭自适应弹出窗口呈现

Unwind segue doesn't dismiss adaptive popover presentation when not modal

iOS 9 beta 的更新:Apple 可能已经为 iOS 9 修复了此问题。如果您为 iOS 8 解决了这个问题,确保它在 iOS 9.

上也能正常工作

在情节提要中,我创建了一个弹出式展示转场以通过按钮展示导航和视图控制器,并创建了一个展开转场。

在纵向模式下,模态(全屏)显示如预期的那样 unwound/dismissed。

在横向模式下,也会调用展开转场,但是弹出窗口显示不会自动关闭。

我是不是错过了什么连接?我必须自己关闭弹出窗口显示吗?

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)__unused sender
{
    if ([[segue identifier] isEqualToString:@"showSelectBookChapter"])
    {
        UINavigationController *navigationController = segue.destinationViewController;

        if ([navigationController.topViewController isKindOfClass:[BIBLESelectViewController class]])
        {
            BIBLESelectViewController *selectViewController = (BIBLESelectViewController *)navigationController.topViewController;
            selectViewController.initialBookChapterVerse = self.bookChapterVerse;
        }
    }
}

- (IBAction)unwindToBIBLEChapterViewController:(UIStoryboardSegue *)segue
{
    if ([segue.identifier isEqualToString:@"unwindToBIBLEChapterViewController"]) {
        if ([segue.sourceViewController isKindOfClass:[BIBLESelectViewController class]])
        {
            BIBLESelectViewController *sourceViewController = (BIBLESelectViewController *)segue.sourceViewController;
            self.bookChapterVerse = sourceViewController.selectedBookChapterVerse;
            [self.tableView reloadData];

        }
    }
}

更新: 在查看了 gabbler 的示例代码之后,我将问题缩小为在单视图应用程序中弹出窗口关闭正常,但在主从应用程序中没有。

更新二: 这是层次结构的样子(为了简单起见省略了导航控制器),以回答 Luis 提出的问题:

正如我在之前的更新中提到的,我创建了一个新的 master/detail 模板,并直接从详细视图(中的一个按钮)简单地呈现了一个弹出框。它不会解雇。

它 is/must 是 popOver segue 的一种行为,在正常情况下或经常我们需要 popOver 保持在视图中,如果 segue 显示一些重要的东西很烦人,我们只是因为旋转而丢失了该信息设备,我想这就是本机行为的原因。因此,如果我们想让它自动关闭,我们必须自己做出这种行为,这是可行的:

在方法 - (void)viewDidLoad中 detailViewController.m 添加:

[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter]
 addObserver:self selector:@selector(orientationChanged:)
 name:UIDeviceOrientationDidChangeNotification
 object:[UIDevice currentDevice]];

然后创建这个方法:

- (void) orientationChanged:(NSNotification *)note{
UIDevice * device = note.object;
//CGRect rect = [[self view] frame];
switch(device.orientation)
{
    default:
        [self dismissViewControllerAnimated:YES completion:nil];
    break;    }}

你说过在单一视图中会发生你想要的事情,但我在使用 popOvers 时从未见过这种行为。

我运行也遇到过这个问题。我从主视图控制器 (UISplitViewController) 模态地(作为一种形式 sheet)呈现一个视图控制器。问题只出现在 iPad 上(可能也是横向模式下的 iPhone 6+,但我没有检查)。我最终在我的展开操作方法中执行了以下操作(使用 Swift),并且效果很好。

if !segue.sourceViewController.isBeingDismissed() {
    segue.sourceViewController.dismissViewControllerAnimated(true, completion: nil)
}

如果您从 嵌入导航控制器中的视图控制器 作为弹出窗口进行搜索,相应的展开将无法关闭弹出窗口。

这是 -[UINavigationController segueForUnwindingToViewController:fromViewController:identifier] 中的错误。嵌入的导航控制器应该提供一个 segue 来关闭弹出窗口,但它没有。然后解决方法是覆盖它并提供一个工作 segue,我们可以从嵌入式视图控制器获得它。

这是一个只处理展开到导航堆栈的顶视图控制器的部分解决方案:

@implementation MyNavigationController

- (UIStoryboardSegue *)segueForUnwindingToViewController:(UIViewController *)toViewController
                                      fromViewController:(UIViewController *)fromViewController
                                              identifier:(NSString *)identifier
{
  if (toViewController == self.topViewController && fromViewController.presentingViewController == self)
    return [toViewController segueForUnwindingToViewController:toViewController
                                            fromViewController:fromViewController
                                                    identifier:identifier];
  else
    return [super segueForUnwindingToViewController:toViewController
                                 fromViewController:fromViewController
                                         identifier:identifier];
}

@end

它适用于 iOS 8 landscape/portrait iPad 和 landscape/portrait iPhone。逻辑应该足够健壮以在 iOS 9.

上生存

mbeaty 的修复很好,但正如其他人指出的那样,这个错误似乎知道在 iOS 9 中修复,并且它也不适用于通用设备设计。我已经调整了他的回答来处理这两种情况。这是代码:

@IBAction func yourUnwindSegue(segue: UIStoryboardSegue) {
    if #available(iOS 9, *) {
        return  // bug fixed in iOS 9, just return and let it work correctly
    }
    // do the fix for iOS 8 bug

    // access your SplitViewController somehow, this is one example
    let appDelegate  = UIApplication.sharedApplication().delegate as! AppDelegate
    let splitVC = appDelegate.window!.rootViewController as! YourSplitViewController

    // if the source isn't being dismissed and the splitView isn't
    //    collapsed (ie both windows are showing), do the hack to
    //    force it to dismiss
    if !segue.sourceViewController.isBeingDismissed() && splitVC.collapsed == false {
        segue.sourceViewController.dismissViewControllerAnimated(true, completion: nil)
    }
}

这首先检查 iOS 9 是否为 运行,然后退出,因为错误似乎已修复。这将防止多个视图被忽略的问题。还要确保仅在 splitView 显示两个 windows 时才进行此修复(以使其仅在 iPad 和 iPhone 6 Plus 横向以及未来的设备上发生)我添加了检查以进行确保它没有折叠。

我没有详尽地检查过这个,但它似乎有效。也不是说我的应用程序设置为 iOS 7 分钟,我不知道这个错误是否存在,所以如果你支持 iOS 8.[=11 以下,你可能需要调查一下=]