18

我正在编写一个具有 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];

                                          }];

}
4

8 回答 8

44

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

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];

斯威夫特 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)
于 2012-08-06T00:17:44.827 回答
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 方法中(项目列表)。

于 2012-08-06T00:05:48.347 回答
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];
    }   
}

Now, in your main root controller,when a tableview row is selected do something like this when pushing to controllerB in your tableView did select method

[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;

然后就在你弹回控制器A之前,你设置了标志

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

就是这样。您不必对控制器C 做任何事情。还有其他一些方法可以做,但这对于您的需求来说非常简单。希望它对你有帮助。

于 2012-08-06T01:19:03.213 回答
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
于 2014-09-10T17:08:34.533 回答
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];
于 2015-06-17T07:39:20.237 回答
0

我认为这是不可能的,因为弹回会释放所有内容。

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

于 2012-08-05T23:40:36.557 回答
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. 用你想要的顶视图控制器替换 GroupViewController()
于 2016-04-21T03:57:09.670 回答
0

如果您想做的是在同一个导航控制器中以任何方式导航...您可以访问 navigationStack AKA viewControllers,然后按照您想要的顺序设置 viewcontrollers,或者添加或删除一些...这是最干净的和本地的方式来做到这一点。

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

做任何必要的验证,这样你就不会得到任何异常。

于 2016-07-29T21:16:31.493 回答