UISplitViewController 在主要和详细信息中都带有导航堆栈 - 如何从其中一个堆栈中删除 VC?

UISplitViewController with nav stacks in both master and detail - how to remove a VC from one of the stacks?

我正在调试遗留代码,这总是很有趣。旧代码试图模拟 splitView 委托方法,导致各种问题 - 主要是崩溃:在纵向的 Plus 设备上,旋转到横向导致崩溃 - 如果没有详细视图集,旧代码试图在一个狡猾的黑客中创建一个,它只是没用......

我的应用程序是基于 UISplitViewController 的,我在 splitView 的主侧和详细侧都有一个导航堆栈。

通过阅读 SO 并使用 this example 并能够实现 UISplitViewController 委托方法,并且在旋转方面一切正常,并在适当的时候显示正确的 master/detail 视图.这是我的实现:(为代码片段墙道歉)

- (BOOL)splitViewController:(UISplitViewController *)splitViewController collapseSecondaryViewController:(UIViewController *)secondaryViewController ontoPrimaryViewController:(UIViewController *)primaryViewController {

    if ([secondaryViewController isKindOfClass:[UINavigationController class]]
        && [[(UINavigationController *)secondaryViewController topViewController] isKindOfClass:[AECourseHTMLTableViewController class]]
        && ([(AECourseHTMLTableViewController *)[(UINavigationController *)secondaryViewController topViewController] htmlContentEntry] == nil)) {
        // If the detail controller doesn't have an item, display the primary view controller instead
        return YES;
    }
    return NO;
}

还有另一个 splitView 委托方法 - 请参阅代码中的注释以了解我遇到的问题。

- (UIViewController *)splitViewController:(UISplitViewController *)splitViewController separateSecondaryViewControllerFromPrimaryViewController:(UIViewController *)primaryViewController {
    // If detail view already exists
    if ([primaryViewController isKindOfClass:[UINavigationController class]]) {
        for (UIViewController *controller in [(UINavigationController *)primaryViewController viewControllers]) {
            if ([controller isKindOfClass:[UINavigationController class]] && [[(UINavigationController *)controller visibleViewController] isKindOfClass:[AECourseHTMLTableViewController class]]) {
                return controller;
            }
        }
    }

    // Create detail view
    UINavigationController *navController = [self.storyboard instantiateViewControllerWithIdentifier:@"CourseHTMLNav"];
    if ([navController.viewControllers.firstObject isKindOfClass:[AECourseHTMLTableViewController class]]) {
    AECourseHTMLTableViewController *courseViewController = navController.viewControllers.firstObject;
    [self configureViewController:courseViewController entry:self.contentSection.sections[0] indexPath:courseViewController.currentIndexPath];
    }

    // Enable back button
    UIViewController *controller = [navController visibleViewController];
    controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
    controller.navigationItem.leftItemsSupplementBackButton = YES;

    if (!self.splitViewController.isCollapsed) {
        UINavigationController *navController = self.splitViewController.viewControllers.firstObject;
        AEContentMenuTableViewController *contentMenuVC = navController.viewControllers.firstObject; // This controller needs to be master in Landscape

        NSMutableArray<UIViewController *> *controllers = [navController.viewControllers mutableCopy]; // Contains 3 controllers, first needs removed
        NSMutableArray *toDelete = [NSMutableArray new];

    for (UIViewController *viewController in controllers)
        if ([viewController isKindOfClass:[contentMenuVC class]] || [viewController isKindOfClass:[AECourseHTMLTableViewController class]]) {
            [toDelete addObject:viewController]; // Remove first VC, so master should become AEContentMenuVC?
            break;
        }

    // Remove the object
    [controllers removeObjectsInArray:toDelete];

    // Set viewControllers
    navController.viewControllers = controllers;
    }
    return navController;
  }

AECourseHTMLTableViewController 有 next/prev 个按钮 select tableview 菜单的 tableview 中的下一行 class class (AEContentMenuTableViewController) .我有一个委托函数可以告诉我当前 indexPath 其中 AECourseHTML...AEContentMenu... 使用,并且在调用它时,它 select 是菜单表视图行并实例化一个新的 AECourseHTML... 并推送它。

这就是我卡住的地方。在纵向中,按 next/prev 没问题,它 select 是正确的行并且按预期工作。但是一旦我旋转设备,主视图和详细视图都会显示详细视图。我可以在主视图上按 "Back",它会将我带到正确的 AEContentMenu... class。如代码片段注释中所述,我需要从主堆栈(实际上是第一个对象)中删除一个 ViewController,并且 AEContentMenu... 应该成为该堆栈的第一个对象 - 所以在旋转时,应该成为主视图。

很抱歉这么长时间post,我已经为此苦思了好几个星期了,我想在这个问题中包含尽可能多的信息。提前致谢。

我找到了适合我的用例的解决方案。它可能不是最干净的代码,但我对我得到的代码很满意。

splitViewController:collapseSecondaryViewController:ontoPrimaryViewController: 保持不变。我已经用解决方案更新了我的 splitViewController:separateSecondaryViewControllerFromPrimaryViewController: 委托方法。欢迎任何反馈。

- (UIViewController *)splitViewController:(UISplitViewController *)splitViewController separateSecondaryViewControllerFromPrimaryViewController:(UIViewController *)primaryViewController {
   // If detail view already exists
   if ([primaryViewController isKindOfClass:[UINavigationController class]]) {
       for (UIViewController *controller in [(UINavigationController *)primaryViewController viewControllers]) {
           if ([controller isKindOfClass:[UINavigationController class]] && [[(UINavigationController *)controller visibleViewController] isKindOfClass:[AECourseHTMLTableViewController class]]) {
               return controller;
           }
       }
   }

   // Return CourseVC
   UINavigationController *navController = splitViewController.viewControllers.firstObject;
   UIViewController *viewController;
   for (viewController in navController.viewControllers) {
       if ([navController.viewControllers.lastObject isKindOfClass:[AECourseHTMLTableViewController class]]) {
           return viewController;
       } else {
           // Create detail view
           UINavigationController *navController = [self.storyboard instantiateViewControllerWithIdentifier:@"CourseHTMLNav"];
           if ([navController.viewControllers.firstObject isKindOfClass:[AECourseHTMLTableViewController class]]) {

               // Enable back button
               UIViewController *controller = [navController visibleViewController];
               controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
               controller.navigationItem.leftItemsSupplementBackButton = YES;

               AECourseHTMLTableViewController *courseViewController = navController.viewControllers.firstObject;
               // If next/prev has been tapped, configure current ContentHTML
               if (self.currentContentHTML) {
                   [self configureViewController:courseViewController entry:self.currentContentHTML indexPath:courseViewController.currentIndexPath];
               } else {
                   // Create new ContentHTML from first row of AEContentMenuVC
                   [self configureViewController:courseViewController entry:self.contentSection.sections[0] indexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
               }
               return navController;
           }
         }
   }
   return navController;
}

你最上面的 if 语句应该 return nil。由于您 return 使用嵌套导航控制器,因此您错过了弹出主导航顶部控制器的默认行为,这是必需的,因此可以将其放置在右侧。

默认行为会找到嵌套的导航控制器并将其弹出。然而,您仍然需要自己搜索它的原因是,如果它不存在,那么您需要像您所做的那样从情节提要中加载详细导航。