如何弹回到根视图控制器,然后推送到另一个视图?

时间:2012-08-05 23:18:58

标签: ios xcode cocoa uiviewcontroller uinavigationcontroller

我正在编写一个包含3个视图控制器的简单应用程序。根视图控制器是item listing基本表视图。关闭此视图控制器,我根据一些用户交互推送两个不同的视图控制器 - create item视图控制器或view item视图控制器。

因此,故事板看起来就像V或其他东西。

在我的create item视图控制器上,我希望它在用户创建新项目时弹回到根视图控制器,然后推送到view item控制器以便我可以查看新创建的项目。

我似乎无法让这个工作。弹回根视图控制器很容易,但是我无法推送view item控制器。

有什么想法吗?我已经粘贴了我的代码,如下所示。 pop功能有效,但新视图永远不会出现。

- (void) onSave:(id)sender {

    CLLocation *currentLocation = [[LocationHelper sharedInstance] currentLocation];

    // format the thread object dictionary
    NSArray* location = @[ @(currentLocation.coordinate.latitude), @(currentLocation.coordinate.longitude) ];
    NSDictionary* thread = @{ @"title": _titleField.text, @"text": _textField.text, @"author": @"mustached-bear", @"location": location };

    // send the new thread to the api server
    [[DerpHipsterAPIClient sharedClient] postPath:@"/api/thread"
                                       parameters:thread
                                          success:^(AFHTTPRequestOperation *operation, id responseObject) {

                                              // init thread object
                                              Thread *thread = [[Thread alloc] initWithDictionary:responseObject];

                                              // init view thread controller
                                              ThreadViewController *viewThreadController = [[ThreadViewController alloc] init];
                                              viewThreadController.thread = thread;

                                              [self.navigationController popToRootViewControllerAnimated:NO];
                                              [self.navigationController pushViewController:viewThreadController animated:YES];

                                          }
                                          failure:^(AFHTTPRequestOperation *operation, NSError *error) {

                                              [self.navigationController popToRootViewControllerAnimated:YES];

                                          }];

}

8 个答案:

答案 0 :(得分:39)

如果我理解正确,你就有一堆视图控制器:

A (root) - B - C - D - E

你希望它成为:

A (root) - F

右?在那种情况下:

NSArray *viewControllers = self.navigationController.viewControllers;
NSMutableArray *newViewControllers = [NSMutableArray array];

// preserve the root view controller
[newViewControllers addObject:[viewControllers objectAtIndex:0]];
// add the new view controller
[newViewControllers addObject:viewThreadController];
// animatedly change the navigation stack
[self.navigationController setViewControllers:newViewControllers animated:YES];

Swift 4

// get current view controllers in stack and replace them
let viewControllers = self.navigationController!.viewControllers
let newViewControllers = NSMutableArray()

// preserve the root view controller
newViewControllers.add(viewControllers[0])
// add the new view controller
newViewControllers.add(viewThreadController)
// animatedly change the navigation stack
self.navigationController?.setViewControllers(newViewControllers as! [UIViewController], animated: true)

答案 1 :(得分:8)

我认为 [self.navigationController pushViewController:viewThreadController animated:YES]; 正在使用与之前的语句不同的NavigationController。 因为在弹出到根视图控制器后,您将松开您所在的导航控制器。请使用此代码解决此问题

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

我也认为这不会解决你的整个问题。您可能会收到一条错误消息,指出两个快速弹出和推送可能会导致NavigationController无效  要解决这个问题,您可以将NavigationController推送到第二个视图控制器的viewDidDissappear方法中,或者将其推送到主视图控制器的viewDidAppear方法中(项目列表)。

答案 2 :(得分:6)

完成您想要做的事情的一种简单方法是在主根视图控制器中构建一些简单的逻辑 - (void)viewWillAppear方法并使用委托回调来翻转逻辑开关。基本上是根控制器的“后向引用”。这是一个简单的例子。

主根控制器(考虑这个控制器a) - 好称它为controllerA 设置属性以跟踪跳转状态

@property (nonatomic) BOOL jumpNeeded;

中设置一些逻辑
- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    self.jumpNeeded ? NSLog(@"jump needed") : NSLog(@"no jump needed");

    if (self.jumpNeeded) {
        NSLog(@"jumping");
        self.jumpNeeded = NO;
        [self performSegueWithIdentifier:@"controllerC" sender:self];
    }   
}

现在,在主根控制器中,当选择tableview行时,执行类似这样的操作 在推送到tableView中的controllerB时,确实选择了方法

[self performSegueWithIdentifer@"controllerB" sender:self];

然后实现你准备segue方法

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

  //setup controller B
  if([segue.identifier isEqualTo:@"controllerB"]){
    ControllerB *b = segue.destinationViewController;
    b.delegate = self;  //note this is the back reference
  }

  //implement controller c here if needed
}

现在转到controllerB 您需要设置一个名为“delegate”的属性来保存后引用 并且您需要从根控制器

导入头文件
#import "controllerA"

@property (nonatomic,weak) controllerA *delegate;

然后在回弹到controllerA之前,设置标志

   self.delegate.jumpNeeded = YES;
    [self.navigationController popViewControllerAnimated:YES];

就是这样。您无需对controllerC执行任何操作。还有其他一些方法可以做,但这对您的需求非常直接。希望它适合你。

答案 3 :(得分:5)

根据Dave DeLong在我们的应用程序中使用的答案在UINavigationController上共享一个类别,以保持后退按钮始终按要求运行。

@implementation UINavigationController (PushNewAndClearNavigationStackToParent)

- (void) pushNewControllerAndClearStackToParent:(UIViewController*)newCont animated:(BOOL)animated
{
    NSArray *viewControllers = self.viewControllers;
    NSMutableArray *newViewControllers = [NSMutableArray array];
    
    // preserve the root view controller
    [newViewControllers addObject:[viewControllers firstObject]];
    // add the new view controller
    [newViewControllers addObject:newCont];
    // animatedly change the navigation stack
    [self setViewControllers:newViewControllers animated:animated];
}

@end

答案 4 :(得分:1)

NSArray *viewControllers = self.navigationController.viewControllers;
NSMutableArray *newViewControllers = [NSMutableArray array];

// preserve the root view controller
for(int i = 0; i < [viewControllers count];i++){
    if(i != [viewControllers count]-1)
        [newViewControllers addObject:[viewControllers objectAtIndex:i]];
}
// add the new view controller
[newViewControllers addObject:conversationViewController];
// animatedly change the navigation stack
[self.navigationController setViewControllers:newViewControllers animated:YES];

答案 5 :(得分:0)

我不认为这是可能的,因为弹出会取消所有内容。

我认为更好的方法是将数据放在模型单例类上,弹出到rootviewcontroller并监听pop结束。然后检查模型上是否存储了一些数据,以便您知道是否应该推送新的viewcontroller。

答案 6 :(得分:0)

我用Dave的答案作为灵感,并为Swift做了这个:

let newViewControllers = NSMutableArray()
newViewControllers.addObject(HomeViewController())
newViewControllers.addObject(GroupViewController())
let swiftArray = NSArray(array:newViewControllers) as! Array<UIViewController>
self.navigationController?.setViewControllers(swiftArray, animated: true)
  1. 将HomeViewController()替换为您想要底视图控制器
  2. 的任何内容
  3. 将GroupViewController()替换为您希望顶视图控制器为
  4. 的任何内容

答案 7 :(得分:0)

如果你想要做的是在同一导航控制器内以任何方式导航......你可以访问navigationStack A.K.A. viewControllers然后按照你想要的顺序设置viewcontrollers,或添加或删除一些... 这是最干净,最原生的做法。

        UINavigationController* theNav = viewControllerToDismiss.navigationController;
        UIViewController* theNewController = [UIViewController new];
        UIViewController* rootView = theNav.viewControllers[0];
        [theNav setViewControllers:@[
                                     rootView,
                                     theNewController
                                     ] animated:YES];

进行任何必要的验证,以免发生任何异常。