Update: @autresphere on Twitter has pointed out to me that you can set the animation duration to 0 and no animation will occur. This works and is more effective than the block-based method below. I also did a little further testing, and the animations block is performed synchronously, but the completion block is not. They are both performed on the main thread, of course. I’ve updated the GitHub repository with this new code.

Original Post:

I’ve been working a lot recently with Container View Controllers, and in a lot cases, you want to provide an API for choosing whether the transition should be animated or not. This is useful if the user of the API wants to rebuild the navigation controller stack on first launch. In SKNavigationController, I was doing these as separate blocks in an if/else construct, and repeating code.

- (void) pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
 
    newViewController.view.frame = //original frame
    [self addChildViewController:newViewController];
 
    if (!animated) {
        [self.view addSubview:newViewController.view];
        [oldViewController.view removeFromSuperview];
 
        newViewController.view.frame = //new frame
 
        [newViewController didMoveToParentViewController:self];
    } else {
        [self transitionFromViewController:oldViewController
               		  toViewController:newViewController
                   		  duration:0.35f
                       		   options:0
				animations:^{
					newViewController.view.frame = //new frame
				}
				completion:^(BOOL finished) {
					[newViewController didMoveToParentViewController:self];
				}];
    }
}

We’re trying not to repeat ourselves, and we already have these handy blocks that describe the state after our animation is complete ( animations ) and what to do when the animation is complete ( completion ). Let’s just turn these into standalone blocks, and call them right on the main thread if the pushing is not animated.

- (void) pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
    newViewController.view.frame = //original frame     
 
    [self addChildViewController:newViewController];
 
    void (^animations)(void) = ^{
        newViewController.view.frame = //new frame
    };
 
    void (^completion)(BOOL finished) = ^(BOOL finished){
        [newViewController didMoveToParentViewController:self];
    };
 
    if (!animated) {
        [self.view addSubview:newViewController.view];
        [oldViewController.view removeFromSuperview];
 
        animations();
        completion(YES);
    } else {
	[self transitionFromViewController:oldViewController
			  toViewController:newViewController
				  duration:0.35f
				   options:0
				animations:animations
				completion:completion];
    }
}

A little weirder looking if you like Objective-C syntax and get freaked out by the carets (^) in the block syntax, but much cleaner and easier to maintain.

I’ve updated the SKNavigationController GitHub repository to reflect this.