So, after creating a few tests, I found that the problem can be caused by presenting another view controller from the didAppear or willAppear methods. The latter seems fine but the missing call to didShowViewController after viewDidAppear seems like a bug to me.
to avoid this issue you could create a completion block in a subclass of UINavigationController for pushing view controllers and only start your pushed view controller off once the push is complete. Something similar to this perhaps:
Completion handler for UINavigationController "pushViewController:animated"?
For example (warning! untested):
@interface PbNavigationController : UINavigationController <UINavigationControllerDelegate>
@property (nonatomic,copy) dispatch_block_t completionBlock;
@property (nonatomic,strong) UIViewController * pushedVC;
@end
@implementation PbNavigationController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.delegate = self;
}
return self;
}
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
NSLog(@"didShowViewController:%@", viewController);
if (self.completionBlock && self.pushedVC == viewController) {
self.completionBlock();
}
self.completionBlock = nil;
self.pushedVC = nil;
}
-(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
if (self.pushedVC != viewController) {
self.pushedVC = nil;
self.completionBlock = nil;
}
}
-(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated completion:(dispatch_block_t)completion {
self.pushedVC = viewController;
self.completionBlock = completion;
[self pushViewController:viewController animated:animated];
}
@end
You could probably do a bunch more to synchronise the completion block and the pushedVC....