.
Hi, everyone.
I have a custom ViewController(1) and presented another ViewController(2) modally.
While Modal ViewController(2) is showing, it received memory warning and changed orientation.
After then, I dismissed Modal ViewController(2).
And I checked the sequence of call back function on ViewController(1).
willRotateToInterfaceOrientation
loadView
viewDidLoad
willAnimateRotationToInterfaceOrientation
didRotateFromInterfaceOrientation
...
is it normal to be called willRotateToInterfaceOrientation function before loadView?
Is it normal? What does that matter? If your results are correct, willRotateToInterfaceOrientation is called first.
This is not a huge deal, however: if you need to access the view inside willRotateToInterfaceOrientation, just make sure to access [self view] or self.view in your code. If the view isn't already loaded, it will be loaded right then, calling loadView and viewDidLoad as necessary before returning control back to willRotateToInterfaceOrientation.
If you have outlets set up that are connected when the view loads (probable), just insert [self view]; at the top of the method to force the view to load and the outlets will be connected when it returns. Then you can call self.bigButton.enabled = NO; or whatever else you'd like to do.
Related
I'm running all my apps to make sure it's not just one app, and in every app I have, when I run on the iOS5 simulator or device, the viewWillAppear method gets called twice on every view. I have a simple NSLog(#"1");, and this appears twice in my console every time. Is this just me, or is something going on? (It only gets called once in iOS4)
This is the code calling the view that calls viewWillAppear twice:
CloseDoorViewController *closeVC;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
closeVC = [[ CloseDoorViewController alloc] initWithNibName:#"CloseDoorViewIpad" bundle:nil];
} else {
closeVC = [[ CloseDoorViewController alloc] initWithNibName:#"CloseDoorViewController" bundle:nil];
}
[self.view addSubview:closeVC.view];
[self presentModalViewController:closeVC animated:NO];
It's the -addSubview: method.
When adding or removing view controller's view, someone must call 'View Event' methods such as -viewWillAppear:, etc. of the view controller.
Actually, it wasn't a recommended way to -addSubview:/-removeFromSuperView view controller's view by yourself before iOS 5, because it doesn't call 'View Event' methods (you can/should call it by yourself). Instead, it was recommended to use 'indirect' way to do that, such as -presentModalViewController: you use (it does call 'View Event' methods on your behalf).
On iOS 5, Apple has changed the behavior of -addSubview:/-removeFromSuperView methods to allow direct view management of view controller. So now, when you use those methods on viewController's view, 'View Event' methods will be called automatically.
So it was called twice.
See video "Implementing UIViewController Containment" on here also.
Because you are displaying the view twice.
First time by adding the view as a subview of the current view:
[self.view addSubview:closeVC.view];
Second time by pushing the view's controller on top of current view's controller:
[self presentModalViewController:closeVC animated:NO];
I'm not sure why in iOS4 the viewWillAppear was only called once, because iOS5 is correct to call it twice, given that you are displaying the view twice as explained above.
Just remove one of the lines and it would be fine (I'd recommend removing the addSubview and retain the presentModalViewController one).
If you want to restore the old (iOS 4) behavior in your view controller you should implement the following method:
- (BOOL)automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers {
return NO;
}
Update: since you have edited your question to include a code sample, it is clear what the problem is. Lukman's answer above is correct/excellent.
Original answer before code was included:
I would try putting a breakpoint (or log statement) in the -init method of this class. If that is hit twice, then two view controllers are being created.
(note if you have not already overridden the -init method in this class, make sure you override the designated initializer which is -[UIViewController initWithNibName:bundle:])
http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIViewController_Class/Reference/Reference.html
Interview question: For example, I have 3 classes A,B & C. I navigate from A -> B -> C, while pushing viewDidLoad function calls automatically and during popping viewWillAppear get called. But would it be possible to call my viewDidLoad function while popping?
No, Its not possible.Only viewDidAppear and viewWillAppear will be called by itself.You can call it manually.
All the best.
The viewDidLoad method is called when the view just loaded. Then viewWillAppear is called by the navigation controller when it's about to display the view.
If you want some code to be executed when the view is about to be displayed, be it when it's being pushed or when the top one is being popped, it makes more sense to use the appropriate method viewWillAppear for that, instead of trying to call the viewDidLoad method at a time when it isn't appropriate.
Can't you just move whatever code you have in viewDidLoad to viewWillAppear?
If the question is just "how can we call viewDidLoad while popping?", then it's simple:
- (void) viewWillDisappear:(BOOL)animated
{
[self viewDidLoad];
}
Just as a side note, if you have a view controller stack like A->B, it's possible that viewDidLoad will be called automatically on A when popping B if, while B was on top, the navigation controller unloaded A's view (if the app received a memory warning, for example)
You should not call viewDidLoad manually, it's not designed to be handled this way. Use viewWillAppear, as other users already mentioned.
As for the question whether it may happen that viewDidLoad will be called upon popping from a higher view controller: I imagine that may happen when the device got a low memory warning and unloaded the view controllers further down in the navigation hierarchy. Then the OS has to reload the view, I haven't however tested this and it's possible that this will never happen. The OS only unloads views when they don't have a superview, I didn't check whether upon pushing, views down the hierarchy actually get removed from the hierarchy.
ViewDidLoad should be for view creation.
ViewWillAppear - for Data Interaction if Server Request is Asynchronous. like calling API or any functionality.or any functionality we like to call when view going to appear.
ViewDidAppear - for Data Interaction if Server Request is synchronous.
So in my app delegate I add a call add the myViewController.view to the main window:
1. [window addSubview:myViewController.view];
In myViewController I do the following code in the viewDidAppear method:
2. [self presentModalViewController: yourViewController animated: YES];
In my yourViewController class I do the following to try and go back to the main window
3. [self dismissModalViewControllerAnimated:YES];
My main windows view appears with buttons in all, but the buttons won't react to any click or anything. It's like there is something over them that I can't see.
Also, the main windows button works before this process but doesn't after the process.
Any help would be appreciated.
If the dismiss method call is in the modal view controller (not the parent that presents it), then you actually want to call [self.parentController dismissModalViewControllerAnimated:YES];
There are a number of reasons why things might not be responding to your touches. Here are two that have happened to me:
The frame of the view you want to touch is too small. UIViews can draw outside of their frames, so it might look ok, but not respond if the touch is technically outside of the frame -- you also have to check that all the superview's up the hierarchy also have a large enough frame.
If anything in your view is a UIImageView or child thereof, it won't respond to user touches because UIImageView has userInteractionEnabled set to NO by default. You can fix this just by setting myImageView.userInteractionEnabled = YES;
Edit: Oli pointed out in the comments that dismissModalViewControllerAnimated: should work if called on either self.parentController or simply self, since that method is smart enough to call the parent if needed, according to the docs. The docs also make it sound like this might behave differently if you have multiple model views open at once, though, so I would still consider it cleaner code to call the method on self.parentController directly.
I shift to my view by
[[self navigationController] popToViewController:controller animated:YES];
In that ViewController, I'm not able to get a notice, that it comes back to front (e.g. by viewWillAppear). I want to reload a table, as soon as the view is visible again.
How do I get a notice, that the view comes back on the screen?
----> solved: See my last comment on Corey's answer
viewWillAppear should be called if you are using a UINavigationController.
Are you sure you have added it correctly to the view hierarchy?
Did you check if viewWillDisappear gets called when it goes offscreen?
Did you try viewDidAppear just to make sure?
Did you spell the method name correctly?
To add:
Is the instance of UINavigationController added directly to the UIWindow instance?
The delegate methods like viewWillappear are sent from UIApplication (I believe). UIApplication only "knows" about viewControllers whose views are either:
Added Directly to UIWindow.
Added to a
UINavigationController/UITabBarCOntroller
that is added directly to UIWindow
(or a chain of these that leads to UIWindow).
Specifically, what am I supposed to do with the view that is now hidden after pushing on a new view controller?
In my situation I have a view with animations going on, that continue to execute after the view is off screen.
Is there some accepted convention?
Do I remove the View Controller and View from memory?
Does Cocoa Touch have a convenient method to "Pause" a view (and controller) and remove it from memory, and bring it back into existence when needed (after a pop)?
Do I have to archive it myself and then un-archive it?
Are there any examples you can point me to?
Thanks
Another possible solution is to implement two of the following methods:
– viewWillAppear:
– viewDidAppear:
– viewWillDisappear:
– viewDidDisappear:
You could potentially stop your animation in viewWillDisappear or viewDidDisappear and then restart it in viewWillAppear or viewDidAppear. You could also store any necessary state information about the animation before you stop it.
Under low memory conditions, your controller's 'view' property will automatically be set to nil, if it's not on screen. Then the view will automatically load again when it is needed - and viewDidLoad should get called at that time.
If your view controller is retaining any subviews of the top-level view, then you may want to override the view controller's setView: method, check if the view is being set to nil, and if so, release subviews that you were retaining. Otherwise, the top-level view may never get deallocated.
- (void)setView:(UIView *)view
{
[super setView:view];
if (view == nil)
{
// Release other views
// self.someView = nil;
}
}
Whenever you call pushViewController, the current viewcontroller is stored in an array by navigation controller (this can be accessed using the viewControllers property of navcontroller).
Think of it as a stack. As you call pushViewController, a new viewcontroller is added to the stack on top of the current viewcontroller. But your rootviewcontroller is still in memory. When you call popViewController, that viewcontroller is removed from the stack and released.
So if you want to stop your animation when the view disappears, use the viewWillDisappear method as suggested by Andy.