【问题标题】:UINavigationController popToRootViewController, and then immediately push a new viewUINavigationController popToRootViewController,然后立即推送新视图
【发布时间】:2010-10-31 14:20:16
【问题描述】:

我有一个带有两个选项卡的 tabBarController,其中第一个包含一个 NavigatorController 的实例。 navigatorController 使用自定义视图控制器“peersViewController”启动,该视图控制器列出了 tableView 上的所有网络对等点。选择一个对等点后,“FilesListViewController”的一个实例(列出 c:\ 目录中的文件)被推送到 navigationController 堆栈中。

在这个 filesListViewController 中,我有一个按钮可以让它导航到文档目录。为此,我将接口连接到在 rootViewController 中调用 gotoDirectory:(NSString*)path 方法:

- (void)gotoDirectory:(NSString*)path {
     [[self navigationController] popToRootViewControllerAnimated:YES];
     NSArray *files = [self getFilesFromPeerAtPath:path];
     FilesListViewController *filesVC = [[FilesListViewController alloc] initWithFiles:files];
     [[self navigationController] pushViewController:filesVC animated:YES];
     [filesVC release];
}

但是,当我按下该按钮时,navigationController 确实将我的视图弹出到根视图控制器,但随后我实例化的 FilesListViewController 没有出现。从日志中,我知道确实调用了自定义 initWithFiles 方法,并且确实发生了网络东西来获取文件名。

这件事有些奇怪。我尝试单击第二个选项卡,然后单击返回第一个选项卡,然后哇啦!我需要的文件名在那里。看起来数据和文件ListViewController确实被推入了navigatorController堆栈,但是显示没有刷新而是卡在rootViewController(peersViewController)的屏幕上。

我做错了什么吗?

--本。

-- 发布问题 15 分钟后编辑。我找到了一种解决方法,但让我感到困扰的是 pop 然后 push 不起作用。

- (void)gotoDirectory:(NSString*)path {
     PeersListViewController *rootViewController = (PeersListViewController*)[[[self navigationController] viewControllers] objectAtIndex:0];
     [[self navigationController] setViewControllers:[NSArray arrayWithObject:rootViewController]];
     FilesListViewController *filesVC = [[FilesListViewController alloc] initWithFiles:files];
     [[self navigationController] pushViewController:filesVC animated:YES];
     [filesVC release];
}

navigationController 似乎不应该以这种方式被规避,而且我可能不得不释放原始堆栈中的所有 viewController。然而,这确实适用于 iphone 3.0 模拟器。

如果我使用这段代码,应该如何处理内存释放?我应该获取视图控制器的原始 NSArray 并释放所有内容吗?

【问题讨论】:

    标签: iphone uinavigationcontroller


    【解决方案1】:

    我遇到了一个非常相似的问题(但没有使用标签)。

    我得到了三个viewController : main(root),形式和结果。 当UINavigationController 堆栈是

    "main -> result"
    

    在 btnClick 上,我执行 popToRootViewControllerAnimated,然后按下 formViewCtrl。 为了拥有

    "main -> form"
    

    导航栏标题和后退按钮标签正确,formViewCtrl 的事件被调用。 但是,我仍然看到主视图。

    这是我的“解决方案”

    做了一些测试,我发现没有动画去rootViwCtrl这个工作正常。所以我只用动画来推viewCtrl。

    iPhone 3.0,在设备和模拟器上发现问题。

    如果我有新的东西,我会更新/评论我的帖子。

    【讨论】:

    • 是的,您需要在没有动画的情况下弹出(以便立即发生),然后使用动画进行推送。如果您尝试同时进行两个动画更改(这需要时间来完成),则视图将处于错误状态。
    • 正如描述的那样,这对我不起作用。我认为这是堆栈更改的时间问题(Apple 的动画代码非常脆弱,实现得很差) - 这种技术可能会或可能不会起作用,具体取决于屏幕上还有多少其他内容。
    【解决方案2】:

    如果您想 popToRootViewController 并随后推送另一个 VC,Nick Street 的答案非常有用。

    VC1 -> VC2 -> VC3:从 VC3 => VC2 点击返回按钮,然后是 VC1,这里 OK

    但是,当 VC1 推送 VC2 时,VC2 又会推送 VC3,然后直接从 VC3 回到 VC1 并不能如愿:

    我已经在VC3的-(void)viewWillDisappear:(BOOL)animated中实现了:

    -(void)viewWillDisappear:(BOOL)animated{
    
        ...
        [self.navigationController popToRootViewControllerAnimated:YES];
    }
    

    我还尝试在“后退按钮”中实现它,结果相同:从 VC3 按下后退按钮返回到 VC1:它坏了。实际的VC是VC1,但导航栏还是VC2。玩其他组合,我在 VC2 上得到了 VC1 的 navBar。一团糟。

    Loda 提到了一些关于时间的事情。我认为这是这里的主要问题。我已经尝试了一些东西,所以也许我在这里遗漏了一些东西,但这最终对我有用:

    在 VC3 中:

    -(void)viewWillDisappear:(BOOL)animated {
    
        [super viewWillDisappear:animated];
        // notify VC2
        [[NSNotificationCenter defaultCenter] postNotificationName:backFromV3 object:self];
    }
    

    在 VC2 中:

    -(void)viewDidLoad {
    
        ...
    
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(backFromV3)
                                                     name:@"BackFromV3"
                                                   object:nil];
    }
    
    -(void)backFromV3{
        [NSTimer scheduledTimerWithTimeInterval:0.5 
                                     target:self
                                   selector:@selector(backToRootViewController)
                                   userInfo:nil
                                    repeats:NO];
    }
    
    -(void)backToVC1 {
        self.navigationItem.rightBarButtonItem = nil;
        [self.navigationController popToRootViewControllerAnimated:YES];
    }
    

    当然,做必要的清洁。

    计时器在这里很关键。如果为 0,则中断。 0.5 好像没问题。

    这对我来说非常有效。有点重,但我找不到任何可以解决问题的方法。

    【讨论】:

      【解决方案3】:

      我看到这个关于弹出到根目录然后推送新 ViewController 的问题非常普遍,并且这篇文章被浏览了很多,所以我想添加我的一点来帮助其他新人,尤其是那些使用 Xcode 4 的人和故事板。

      在 Xcode 4 中,您有一个故事板。假设您有这些视图控制器:HomeViewController、FirstPageViewController、SecondPageViewController。确保单击它们中的每一个并通过转到 Utilities 窗格-> Attributes Inspector 命名它们的标识符。我们会说它们被命名为 Home、First 和 Second。

      您是 Home,然后您转到 First,然后您希望能够转到 Second,并且能够按返回按钮返回 Home。为此,您需要更改 FirstPageViewController 中的代码。

      要扩展该示例,请在情节提要的 FirstPageViewController 中创建一个按钮。按住 Ctrl 键将该按钮拖入 FirstPageViewController.m。在那里,以下代码将达到预期的结果:

          // Remember to add #import "SecondPageViewController.h" at the top
          SecondPageViewController *secondView = [self.storyboard instantiateViewContorllerWithIdentifier:@"Second"];
          UINavigationController *navigationController = self.navigationController;
          NSArray *array = [navigationController viewControllers];
          // [array objectAtIndex:0] is the root view controller
          NSArray *viewControllersStack = [NSArray arrayWithObjects:[array objectAtIndex:0], secondView, nil];
          [navigationController setViewControllers:viewControllersStack animated:YES];
      

      基本上,您正在抓取视图控制器,按照您想要的顺序将它们排列在堆栈中,然后让导航控制器使用该堆栈进行导航。这是推送和弹出的替代方法。

      【讨论】:

        【解决方案4】:

        您实际上可以保留“返回”动画,然后是“前进”动画,基本上将推送动画延迟到弹出动画完成后。这是一个例子:

        (注意:我的 appDelegate 中有一个名为“transitionTo”的 NSString 变量,最初设置为 @"")...首先,将该变量设置为一个 NSString,以便稍后检测。然后,弹出控制器给你一个漂亮的屏幕过渡回到根:

        appDelegate.transitionTo = @"Another";
        [detailNavigationController popToRootViewControllerAnimated:YES];
        

        然后在 rootviewcontroller 的类中,使用 viewDidAppear 方法:

        -(void)viewDidAppear:(BOOL)animated
        {
            AppDelegate *appDelegate =(AppDelegate*) [UIApplication sharedApplication].delegate;
            if([appDelegate.transitionTo isEqualToString:@"Another"])
            {
                [self transitionToAnotherView];
                appDelegate.transitionTo = @"";
            }
        }
        
        -(void)transitionToAnotherView
        {
            // Create and push new view controller here
            AnotherViewController *controller = [[AnotherViewController alloc] init];
        
            UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:@"Home" style:UIBarButtonItemStyleBordered target:nil action:nil];
            [self.navigationItem setBackBarButtonItem:backButton];
        
            [[self navigationController] pushViewController:controller animated:YES];
        }
        

        所以基本上,弹出到根...当过渡在“viewDidAppear”完成时...然后推送下一个视图。我碰巧保留了一个变量来告诉您希望转换到哪个视图(@"" 表示在我想留在此屏幕上的情况下不进行转换)。

        【讨论】:

          【解决方案5】:

          这个问题的问题和解决方法其实非常简单。

          调用[self.navigationController popToRootViewControllerAnimated:YES]self.navigationController 设置为nil。当您随后调用[self.navigationController pushViewController:someOtherViewController] 时,您实际上是在向nil 发送一条消息,但它什么也不做。

          要解决此问题,只需设置对 navigationController 的本地引用并改用它:

          UINavigationController * navigationController = self.navigationController;
          [navigationController popToRootViewControllerAnimated:NO];
          [navigationController pushViewController:someOtherViewController animated:YES];
          

          正如 Jason 所说,popToRootViewController 必须在没有动画的情况下执行才能正常工作。

          感谢jpimbert on the Apple forums 指出这一点。

          【讨论】:

          • 嗯,这样我得到:在推送调用之后对 的开始/结束外观转换的不平衡调用编辑:啊,那是因为我正在为 pop 调用设置动画
          • 嘿……我在一年前做了这个修复,它一直工作到 iOS8 发布。它在 iOS8 版本之前工作,但在 iOS8 上不工作。所以我在推送视图控制器中将动画设置为 NO 以使其工作。我想知道是否有人在 iOS8 上遇到过这个问题,以及是否有其他更好的解决方案。
          【解决方案6】:

          我找到了一种解决方法,但我无法解释它为什么起作用: 1.首先推动需要的控制器。 2.然后弹出到你想要的那个。

          这完全不合逻辑,但它适用于我的情况。 为了清楚起见,我在以下场景中使用它: 第一个屏幕 -> 进入加载屏幕 -> 第二个屏幕 当我在第二个屏幕上时,我不想让加载屏幕在堆栈中,当点击返回时我应该转到第一个屏幕。

          问候, 韦斯科·科列夫

          【讨论】:

          • 这真的不应该工作。但确实如此。在 3.0 中,我发现经典方法(直接操作 viewControllers 数组)并不总是按预期工作,所以我正在尝试这种解决方法。
          猜你喜欢
          • 2014-09-16
          • 2014-10-03
          • 2012-09-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-01-01
          相关资源
          最近更新 更多