Animating another viewcontroller storyboard scene programatically - objective-c

I am working through a tutorial that is demonstrating a facebook/path left hand nav
http://hsapkota.com.au/index.php/blog/ios-iphone-ipad/28-tutorial-creating-gmail-facebook-like-menu-navigation-in-ios
Everything is working as expected, however I wanted to add a close navigation button in the navigation table, but I can't seem to fire the same method or access the storyboard scene from the navigation class
this is an example of one way I was trying to perform the task
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
NSString * storyboardName = #"MainStoryboard_iPhone";
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:storyboardName bundle: nil];
UINavigationController * vc = [storyboard instantiateViewControllerWithIdentifier:#"main"];
[UIView animateWithDuration:0.2f
delay:0.0
options:UIViewAnimationCurveLinear
animations:^{
CGAffineTransform trans = CGAffineTransformMakeTranslation(200.0, 0.0);
vc.view.transform= trans;
}
completion:^(BOOL finished){
}
];
}
'main' is the storyboardID I that is I would like to animate, however on performing an NSLog on 'vc.navigationController' I get a NULL return - although logging 'vc' returns the class name associated with the correct storyboard scene
Any help would be appreciated I just can't get my head around it!
-edit
I thought I was able to edit the 'main view' calling superview in my transform
self.view.superview.transform= trans
however this animates both viewcontrollers and also renders 'main view' useless as non of the tap gestures respond in this view now...
Any further thoughts?

Okay after a lot of faffing about I managed to get something to work
I needed to contact the appdelegate in order to access the other viewcontroller in context
my code is now
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
AppDelegate* appDel = (AppDelegate*)[[UIApplication sharedApplication] delegate];
MainView *mv = (MainView *)appDelegate.window.rootViewController;
[UIView animateWithDuration:0.2f
delay:0.0
options:UIViewAnimationCurveLinear
animations:^{
CGAffineTransform trans = CGAffineTransformMakeTranslation(-0.0, 0.0);
mv.view.transform= trans;
}
completion:^(BOOL finished){
}
];
}

Related

Custom segue, but leave the previous scene showing

Imagine a custom segue ...
-(void)perform
{
UIView *sv = ((UIViewController *)self.sourceViewController).view;
UIView *dv = ((UIViewController *)self.destinationViewController).view;
UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
[window insertSubview:dv aboveSubview:sv];
[dv coverFromRight:0 then:^
{
[self.sourceViewController
presentViewController:self.destinationViewController
animated:NO completion:nil];
}];
}
Which in fact, only PARTIALLY (!) covers the "underneath, previous" scene,
and in fact DOES NOT call "presentViewController", so, the "underneath, previous" scene in fact keeps operating normally.
-(void)perform
{
UIView *sv = ((UIViewController *)self.sourceViewController).view;
UIView *dv = ((UIViewController *)self.destinationViewController).view;
UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
[window insertSubview:dv aboveSubview:sv];
[dv coverButOnlyHalfWay:0 then:^
{
}];
}
Essentially, is this possible?
In fact, I've found from experiment the above works (!!). BUT when you come to the custom unwind segue, it does not work: everything crashes. (Perhaps as you'd expect.)
What's the situation? is there a way to make a custom segue, which, covers only say half the "original, underneath" scene and leaves that scene running?
(I appreciate you can just implement this using a container view, but it's not as clean as a whole segue scene.)
Why use a segue? You can just add your view as a subview and position it correct using CGRectMake, this would be much easier.
// Size Your View with X, Y coordinates
[viewController.view setFrame:CGRectMake(0, 0, 320, 192)];
[self.view addSubview:viewController.view];
[viewController didMoveToParentViewController:self];
[self addChildViewController:viewController];

Restore pre-iOS7 UINavigationController pushViewController animation

So. Just started transitioning my IOS code to IOS7, and ran into a bit of problem.
I've got a UINavigationController, which has child ViewControllers and I'm using pushViewController to display the next views. To create a parallax animation with a set of images, if customized the UINavigationController to animate a set of UIImageViews and my child ViewControllers all have a self.backgroundColor = [UIColor clearColor], transparency.
Since iOS7, the way the UINavController animates it child vc's, is updated, by partially moving the current view controller and on top pushing the new viewcontroller, my parallax animation looks crap. I see the previous VC move a bit and then disappear. Is there any way I can restore the previous UINavigationController pushViewController animation? I can't seem to find this in the code.
WelcomeLoginViewController* welcomeLoginViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"WelcomeLogin"];
[self.navigationController pushViewController:welcomeLoginViewController animated:YES];
Even tried using:
[UIView animateWithDuration:0.75
animations:^{
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[self.navigationController pushViewController:welcomeLoginViewController animated:NO];
[UIView setAnimationTransition:<specific_animation_form> forView:self.navigationController.view cache:NO];
}];
Does anyone have any clue?
I managed to workaround the new transition type by creating a category for UINavigationController. In my case I needed to revert it to the old transition style because I have transparent viewControllers that slide over a static background.
UINavigationController+Retro.h
#interface UINavigationController (Retro)
- (void)pushViewControllerRetro:(UIViewController *)viewController;
- (void)popViewControllerRetro;
#end
UINavigationController+Retro.m
#import "UINavigationController+Retro.h"
#implementation UINavigationController (Retro)
- (void)pushViewControllerRetro:(UIViewController *)viewController {
CATransition *transition = [CATransition animation];
transition.duration = 0.25;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromRight;
[self.view.layer addAnimation:transition forKey:nil];
[self pushViewController:viewController animated:NO];
}
- (void)popViewControllerRetro {
CATransition *transition = [CATransition animation];
transition.duration = 0.25;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromLeft;
[self.view.layer addAnimation:transition forKey:nil];
[self popViewControllerAnimated:NO];
}
#end
I have the same problem with clear background colors and crappy animations, so I create custom transitioning for ViewController with new iOS7 API. All you need is simply set a delegate for your navigation controller:
// NavigationController does not retain delegate, so you should hold it.
self.navigationController.delegate = self.navigationTransitioningDelegate;
Just add this files into your project: MGNavigationTransitioningDelegate.
I had a problem where when UIViewController A did a pushViewController to push UIViewController B, the push animation would stop at about 25%, halt, and then slide B in the rest of the way.
This DID NOT happen on iOS 6, but as soon as I started using iOS 7 as the base SDK in XCode 5, this started happening.
The fix is that view controller B did not have a backgroundColor set on its root view (the root view is the one that is the value of viewController.view, that you typically set in loadView). Setting a backgroundColor in that root view's initializer fixed the problem.
I managed to fix this as follows:
// CASE 1: The root view for a UIViewController subclass that had a halting animation
- (id)initWithFrame:(CGRect)frame
{
if ((self = [super initWithFrame:frame])) {
// Do some initialization ...
// self.backgroundColor was NOT being set
// and animation in pushViewController was slow and stopped at 25% and paused
}
return self;
}
// CASE 2: HERE IS THE FIX
- (id)initWithFrame:(CGRect)frame
{
if ((self = [super initWithFrame:frame])) {
// Do some initialization ...
// Set self.backgroundColor for the fix!
// and animation in pushViewController is no longer slow and and no longer stopped at 25% and paused
self.backgroundColor = [UIColor whiteColor]; // or some other non-clear color
}
return self;
}
First of, I'm not using Storyboard. I tried using UINavigationController+Retro. For some reason, the UINavigationController is having a hard time releasing the UIViewController at the top of the stack. Here's the solution that works for me using iOS 7 custom transition.
Set delegate to self.
navigationController.delegate = self;
Declare this UINavigationControllerDelegate.
- (id<UIViewControllerAnimatedTransitioning>)navigationController (UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC
{
TransitionAnimator *animator = [TransitionAnimator new];
animator.presenting = YES;
return animator;
}
Note that it'll only get called when animated is set to YES. For example
[navigationController pushViewController:currentViewController animated:YES];
Create the animator class extending NSObject. I called mine TransitionAnimator, which was modified from TeehanLax's TLTransitionAnimator inside UIViewController-Transitions-Example.
TransitionAnimator.h
#import <Foundation/Foundation.h>
#interface TransitionAnimator : NSObject <UIViewControllerAnimatedTransitioning>
#property (nonatomic, assign, getter = isPresenting) BOOL presenting;
#end
TransitionAnimator.m
#import "TransitionAnimator.h"
#implementation TransitionAnimator
- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext {
return 0.5f;
}
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext{
UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
if (self.presenting) {
//ANIMATE VC ENTERING FROM THE RIGHT SIDE OF THE SCREEN
[transitionContext.containerView addSubview:fromVC.view];
[transitionContext.containerView addSubview:toVC.view];
toVC.view.frame = CGRectMake(0, 0, 2*APP_W0, APP_H0); //SET ORIGINAL POSITION toVC OFF TO THE RIGHT
[UIView animateWithDuration:[self transitionDuration:transitionContext]
animations:^{
fromVC.view.frame = CGRectMake(0, (-1)*APP_W0, APP_W0, APP_H0); //MOVE fromVC OFF TO THE LEFT
toVC.view.frame = CGRectMake(0, 0, APP_W0, APP_H0); //ANIMATE toVC IN TO OCCUPY THE SCREEN
} completion:^(BOOL finished) {
[transitionContext completeTransition:YES];
}];
}else{
//ANIMATE VC EXITING TO THE RIGHT SIDE OF THE SCREEN
}
}
#end
Use presenting flag to set the direction you want to animate or which ever condition you prefer. Here's the link to Apple reference.
Thanks guys for the feedback. Found a solution in completely recreating the UINavigationController's behavior. When I was nearly finished I ran into Nick Lockwood's solution:
https://github.com/nicklockwood/OSNavigationController
OSNavigationController is a open source re-implementation of UINavigationController. It currently features only a subset of the functionality of UINavigationController, but the long-term aim is to replicate 100% of the features.
OSNavigationController is not really intended to be used as-is. The idea is that you can fork it and then easily customize its appearance and behaviour to suit any special requirements that your app may have. Customizing OSNavigationController is much simpler than trying to customize UINavigationController due to the fact that the code is open and you don't need to worry about private methods, undocumented behavior, or implementation changes between versions.
By overriding my UINavigationController with his code, I was able to work with background images in UINavigationcontrollers
Thanks!
Simply add in:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
This:
[[self window] setBackgroundColor:[UIColor whiteColor]];
The final result:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions (NSDictionary *)launchOptions {
[[self window] setBackgroundColor:[UIColor whiteColor]];
// Override point for customization after application launch.
return YES;
}
Apparently in iOS7 there's a new way define your own custom UIViewController transitions. Look in the docs for UIViewControllerTransitioningDelegate. Also, here's a link to an article about it: http://www.doubleencore.com/2013/09/ios-7-custom-transitions/
Swift 5 implementation of Arne's answer:
extension UINavigationController {
func pushViewControllerLegacyTransition(_ viewController: UIViewController) {
let transition = CATransition()
transition.duration = 0.25
transition.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
transition.type = .push
transition.subtype = .fromRight
view.layer.add(transition, forKey: nil)
pushViewController(viewController, animated: false)
}
func popViewControllerLegacyTransition() {
let transition = CATransition()
transition.duration = 0.25
transition.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
transition.type = .push
transition.subtype = .fromLeft
view.layer.add(transition, forKey: nil)
popViewController(animated: false)
}
}
Found another great resource to help out:
http://www.teehanlax.com/blog/custom-uiviewcontroller-transitions
Using iOS7 TLTransitionAnimator to create custom animations
I voted for #Arne's answer, because I find it the most elegant solution to this problem. I would just like to add some code in order to answer to #Bill's problem from his comment on #Arne's solution. Here's comment quote:
Thanks, this works for me. However, when the user taps the Back
button, it reverts to the busted animation (because the back button
doesn't call popViewControllerRetro). – Bill Oct 3 at 12:36
In order to call popViewControllerRetro when back button is pressed, there's a small hack you can perform in order to achieve this. Go into your pushed view controller, import UIViewController+Retro.h and add this code in your viewWillDisappear method:
- (void)viewWillDisappear:(BOOL)animated {
if ([self.navigationController.viewControllers indexOfObject:self] == NSNotFound) {
[self.navigationController popViewControllerRetro];
}
[super viewWillDisappear:animated];
}
This if statement will detect when Back button is pressed and will call popViewControllerRetro from category class.
Best regards.

ViewWillAppear of ParentViewController not called

I am trying to implement a custom UIActionSheet(made up of a ViewController)
I have added a View Controller as a subView to the navigationcontroller of my rootView
- (IBAction)ShowMenu:(id)sender
{
[self.navigationController.view addSubview:self.menuViewController.view];
[self.menuViewController setTest:YES];
[self.menuViewController viewWillAppear:YES];
}
here MenuViewController has a tableview which has few options to select. After selecting I am opening those respective ViewControllers. Suppose I clicked on menu1 and then opened menu1ViewController and it works fine. Now when I close this viewController, I am calling dismissViewController.
and in menuViewController I have written the code to animate by menuviewController to bottom and it works fine.
but the parent of MenuView is TestViewController inside which the functions viewdidAppear is not called when menuviewController animates down.
and thats my problem,
I am using this code to animate by menuViewController to bottom
- (void) slideOut {
[UIView beginAnimations:#"removeFromSuperviewWithAnimation" context:nil];
// Set delegate and selector to remove from superview when animation completes
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(animationDidStop:finished:context:)];
// Move this view to bottom of superview
CGRect frame = self.menusheet.frame;
frame.origin = CGPointMake(0.0, self.view.bounds.size.height);
self.menusheet.frame = frame;
[UIView commitAnimations];
}
// Method called when removeFromSuperviewWithAnimation's animation completes
- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
if ([animationID isEqualToString:#"removeFromSuperviewWithAnimation"]) {
[self.view removeFromSuperview];
}
}
MenuViewController
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if(m_test)
{
[self slideIn];
m_test = FALSE;
}
else
{
[self slideOut];
}
}
IMHO, -[UIViewController viewWillAppear] and -[UIViewController viewDidAppear] would only be called where the callee is added into the view controllers hierarchy by those container-like controllers, like a navigation controller, a tab bar controller.
It would not be called if you just add the view by calling addSubview: in your code. See also.
You could call -viewWillAppear and -viewDidAppear where appropriate, programmatically in your code, before and after you called addSubview: with or without animations.

UIViewController transition - objective-c

I have UIViewControllers A and B, they are allocated in AppDelegate. I need to apply transition to them. How to transit them without reallocating and replacing UIViews?
This code calls from my UIBarButtonItem in UINavigationController:
[UIView transitionFromView:self.view //UIViewController A
toView:appDelegate.secondViewController.view //UIViewController B
duration:0.5
options:UIViewAnimationOptionTransitionFlipFromLeft
This method replaces UIViews in my UIViewControllers, and I can transit them back, or just don't know how to do that. Can you tell me how to do this?
If you're in iOS 5 world and want to jump between various view controllers, you might want to pursue View Controller Containment. Or check out WWDC 2011 session 102.
View controller containment basically assumes that you have some parent view controller which is governing the navigation between multiple child controllers. In your case, the parent view would be one with the navigation bar with the button on it.
Update:
If you pursue containment, you could create a parent view controller that has a nav bar with the button on it. When you load that view, you can add the first child view. Thus viewDidLoad might look like:
- (void)viewDidLoad
{
[super viewDidLoad];
// this is my model, where I store data used by my view controllers
_model = [[MyModel alloc] init];
// let's create our first view controller
OneViewController *controller = [[OneViewController alloc] initWithNibName:#"OneViewController" bundle:nil];
// pass it our model (obviously, `model` is a property that I've set up in my child controllers)
controller.model = _model;
// let's put the new child in our container and add it to the view
[self addChildViewController:controller];
[self configureChild:controller];
[self.view addSubview:controller.view];
[controller didMoveToParentViewController:self];
// update our navigation bar title and the label of the button accordingly
[self updateTitles:controller];
}
The configureChild just does final configuration. As a matter of convenience, I frequently will have a UIView that I've set up in IB (in this case, called childView) which I use for setting up the frame, which gets me out of the world of manually creating frames, but you can do it any way you want:
- (void)configureChild:(UIViewController *)controller
{
// configure it to be the right size (I create a childView in IB that is convenient for setting the size of the views of our child view controllers)
controller.view.frame = self.childView.frame;
}
This is the action if you touch the button in the navigation bar. If you're in the first controller, set up the second controller. If you're in the second controller, set up the first one:
- (IBAction)barButtonTouchUpInside:(id)sender
{
UIViewController *currentChildController = [self.childViewControllers objectAtIndex:0];
if ([currentChildController isKindOfClass:[OneViewController class]])
{
TwoViewController *newChildController = [[TwoViewController alloc] initWithNibName:#"TwoViewController" bundle:nil];
newChildController.model = _model;
[self transitionFrom:currentChildController To:newChildController];
}
else if ([currentChildController isKindOfClass:[TwoViewController class]])
{
OneViewController *newChildController = [[OneViewController alloc] initWithNibName:#"OneViewController" bundle:nil];
newChildController.model = _model;
[self transitionFrom:currentChildController To:newChildController];
}
else
NSAssert(FALSE, #"Unknown controller type");
}
This does the basic transition (including the various containment related calls):
- (void)transitionFrom:(UIViewController *)oldController To:(UIViewController *)newController
{
[self addChildViewController:newController];
[self configureChild:newController];
[self transitionFromViewController:oldController
toViewController:newController
duration:0.5
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
[self updateTitles:newController];
}
completion:^(BOOL finished){
[oldController willMoveToParentViewController:nil];
[oldController removeFromParentViewController];
[newController didMoveToParentViewController:self];
}];
}
This method just sets up the title in the nav bar in our parent view controller based upon which child is selected. It also sets up the button to reference the other controller.
- (void)updateTitles:(UIViewController *)controller
{
if ([controller isKindOfClass:[OneViewController class]])
{
self.navigationItemTitle.title = #"First View Controller"; // current title
self.barButton.title = #"Two"; // title of button to take me to next controller
}
else if ([controller isKindOfClass:[TwoViewController class]])
{
self.navigationItemTitle.title = #"Second View Controller"; // current title
self.barButton.title = #"One"; // title of button to take me to next controller
}
else
NSAssert(FALSE, #"Unknown controller type");
}
This all assumes you are going to create and destroy controllers as you jump between them. I generally do this, but use a model object to store my data so I keep whatever data I want.
You said you don't want to do this "without reallocating and replacing UIViews": If so, you can also change the above code to create both child view controllers up-front and change the transition to be simply jump between them:
- (void)viewDidLoad
{
[super viewDidLoad];
// this is my model, where I store data used by my view controllers
_model = [[MyModel alloc] init];
// let's create our first view controller
_controller0 = [[OneViewController alloc] initWithNibName:#"OneViewController" bundle:nil];
_controller0.model = _model;
[self addChildViewController:_controller0];
[self configureChild:_controller0];
[_controller0 didMoveToParentViewController:self];
// let's create our second view controller
_controller1 = [[OneViewController alloc] initWithNibName:#"OneViewController" bundle:nil];
_controller1.model = _model;
[self addChildViewController:_controller1];
[self configureChild:_controller1];
[_controller1 didMoveToParentViewController:self];
// let's add the first view and update our navigation bar title and the label of the button accordingly
_currentChildController = _controller0;
[self.view addSubview:_currentChildController.view];
[self updateTitles:_currentChildController];
}
- (void)transitionFrom:(UIViewController *)oldController To:(UIViewController *)newController
{
[self transitionFromViewController:oldController
toViewController:newController
duration:0.5
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
[self updateTitles:newController];
}
completion:^(BOOL finished){
_currentChildController = newController;
}];
}
- (IBAction)barButtonTouchUpInside:(id)sender
{
UIViewController *newChildController;
if ([_currentChildController isKindOfClass:[OneViewController class]])
{
newChildController = _controller1;
}
else if ([_currentChildController isKindOfClass:[TwoViewController class]])
{
newChildController = _controller0;
}
else
NSAssert(FALSE, #"Unknown controller type");
[self transitionFrom:_currentChildController To:newChildController];
}
I've seen it both ways, so you can do whatever works for you.
please see here. You basically want to implement UIViewController containment which is a new feature in iOS5. The link provided above provides some code and a link to a github project.
Good luck
t
I found solution for my problem. This code works on iOS 4.x
[UIView beginAnimations:#"transition" context:nil];
[UIView setAnimationDuration:1.0];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlDown
forView:self.navigationController.view
cache:NO];
[self.navigationController
pushViewController:self.alternateView animated:NO];
[UIView commitAnimations];
try
UIViewController* controller1;
UIViewController* controller2;
[controller1 transitionFromViewController:controller1 toViewController:controller2 duration:0.5f options:0 animations:nil completion:nil];
or
if on top of navigationtroller - controller1 then
UINavigationController* nav;
[nav pushViewController:controller2 animated:YES];

viewWillAppear-related problem

Without giving you all my code examples, I'll made this quick.
Has this ever happened to one of you to get viewWillAppear called only the first time it shows up?
I have this problem with all my view.
For example: When my app starts, I get to the StartView which is a main menu. (viewWillAppear gets called) then I press on one button that'll show a navigation controller (viewWillAppear gets called). Then I get back to the main menu (it does not get called) and then I press on the same navigation controller again and it does not get called.
It would be awesome if someone could points me somewhere, I've been searching for this since two days now...
Also if you need more code samples, I can give you some.
For further reading:
That's how I call my navigation controller:
PremierSoinsAppDelegate *AppDelegate = (PremierSoinsAppDelegate *)[[UIApplication sharedApplication] delegate];
UIView *newView = [AppDelegate.navigationController view];
[newView setFrame:CGRectMake(320.0f, 0.0f, 320.0f, 480.0f)];
[UIView beginAnimations:#"RootViewController" context:nil];
[UIView setAnimationDuration:0.3];
newView setFrame:CGRectMake(0.0f, 0.0f, 320.0f, 480.0f)];
UIView commitAnimations];
[AppDelegate.window addSubview:newView];
[AppDelegate.window makeKeyAndVisible];
And that's how I show my menu back:
PremierSoinsAppDelegate *AppDelegate = (PremierSoinsAppDelegate *)[[UIApplication sharedApplication] delegate];
UIView *newView = [AppDelegate.startViewController view];
newView setFrame:CGRectMake(-320.0f, 0.0f, 320.0f, 480.0f)];
UIView beginAnimations:#"StartViewController" context:nil];
UIView setAnimationDuration:0.3];
newView setFrame:CGRectMake(0.0f, 0.0f, 320.0f, 480.0f)];
[UIView commitAnimations];
[AppDelegate.window addSubview:newView];
[AppDelegate.window makeKeyAndVisible];
Thanks A LOT.
You can implement the UINavigationControllerDelegate in your Nav Controller to propagate the viewWillAppear: messages down. You can implement the message like this:
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
if ([viewController respondsToSelector:#selector(viewDidAppear:)]) {
[viewController viewDidAppear:animated];
}
}
Note that this is the viewDidAppear and not ViewWillAppear version, but they're basically the same.
However, you should note that the fact that you need to do this may be a sign that something else is wrong in your controller/view code and you might want to reask the question giving us more context to answer it. In particular, I'm assuming that somewhere outside of the code you're giving us, you're pushing and popping view controllers as per usual for a Nav Controller.
viewWill/DidAppear: will only be called when using a UINavigationController or UITabBarController (or really any system-provided-viewControlller managing class) to manipulate views. If you're manually doing this (as you seem to do in your second code snippet, these messages won't get sent.