UITabBarController and viewDidLoad - swift

Why does viewDidLoad function only called once in UITabBarController's root viewController?
I know viewWillAppear/viewDidAppear can called many times, but why doesn't viewDidLoad called many times?

It's because the tab bar controller gets loaded only one time. That's the process of initialisation and once it's initialised you don't need to do it again. Otherwise it would result in your memory getting loaded with more and more things until you run out of memory.

Related

awakeFromNib called more than once

This is driving me crazy.
I am under the impression that awakeFromNib Method is called only once(even when that view is visited again), correct me if i am wrong.
I have an app with 3 views.
The last one being the subclass of a UIview where i draw using drawRect.
I had a working code with the method awakeFromNib in the last view, with the method being called only once how many ever times i visit the view.
Now i deploy the app to my device and update my Xcode to version 4.
When i run the code again and debug, the method awakeFromNib is called everytime the view is visited.
I dont think update would do such a crazy thing, but i am thoroughly confused.
Is there some kind of a memory leak or am i missing something?
Thank you
I am under the impression that awakeFromNib Method is called only once(even when that view is visited again), correct me if i am wrong.
-awakeFromNib will be called on each instance of a class whenever an instance of that class is loaded from a nib file. You should be able to expect it to only be called once on a particular instance but should handle it being called many times on different instances of any given class.
UIViewControllers will unload their views when they receive a memory warning and their view is not visible. The view will be reloaded the next time the view controller's 'view' property is called. You should understand and support this behavior to minimize your app's memory use as it allows you to only keep the currently visible views in memory at any given time.
It sounds like you are not expecting that controller's view to be unloaded and reloaded from your nib.

Calling viewDidLoad while poping from a navigation class?

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.

popToRootViewControllerAnimated question

I've got next question - why my app dont waiting when i call
[navController popToRootViewControllerAnimated:NO];
... set new viewcontrollers here
I want:
1/ Kill all viewcontrollers by call popToRootViewControllerAnimated - with NO parameter - then i think i can immediately set new view controllers
2/ set new view controllers
But in my logs i see next:
call poptorootview controller
code after poptorootview
dealloc of views and controller (because i call poptorootview)
Why ? How can I detect that all views is killed and navigation controller is poping to root ?
Thanks,
A popped view controller will eventually be released (unless another object retains it), but the reference does not specify exactly when and how it is released. I wouldn't be surprised if it is not immediately released; the UIKit objects may use the view controller for the transition animation. It may be autoreleased not released, which may explain your logs. Also, I wouldn't be surprised inside UINavigationController multiple objects are retaining view controllers in the stack at the same time. Concisely speaking, there is no documented behavior about releasing popped view controllers. All we can be sure of is that it will be released at some point, as otherwise it will lead a memory leak.
Therefore you don't know when the view controllers are actually deallocated. Even if you find out it is subject to change without a notice. However, you can be sure when the view disappeared, using UINavigationController's delegate methods.

loadView Vs init method

Please let me know at what times init and loadView method gets called.
To my knowledge init method gets called only once when view is initialized and loadView is called anytime view is loaded. So, even if you are pushing a new view in the view stack and then popping it then also the loadView of the poped up view should get called. But when I am running my code in debugging mode, both of these methods are getting called once, irrespective of how many times I am loading the same screen. Please let me know if I am missing something.
you are right at some points :)
The init method is being called when the ViewController object is instantiated. The loadView method gets called every time a ViewController should load its view into memory. This can happen before the view is displayed for the first time OR when it should be displayed for a second, third,... time but had been removed from memory before. (this might happen if your app runs out of memory.)
If you want to execute some code every time the view becomes visible, you should have a look at the methods viewWillAppear/viewWillDisappear/viewDidAppear/viewDidDisappear.
loadView is called when you access the view property of your view controller and it's nil.
If the view has been unloaded (viewDidUnload has been called for memory purpose) then loadView will be called again. If not it will not be called.
What you want is viewWillAppear: or viewDidAppear:.

viewDidAppear called twice on the same instance, but only the first time this class loads form NIB

I have a navigation controller. One of the views adds custom subviews in its viewDidAppear:. I notice that the first time I navigate to an instance of this view controller after launching the app, viewDidAppear: invokes twice. If I pop this view off the stack and navigate to it again, viewDidAppear: invokes only once per appearance. All subsequent appearances invoke viewDidAppear: once.
The problem for me is that the first time I get to this view I end up with twice the number of subviews. I work around this problem by introducing a flag variable or some such, but I'd like to understand what is happening and how come I get two invocations in these circumstances.
You should never rely on -viewWillAppear:/-viewDidAppear: being called appropriately balanced with the disappear variants. While the system view controllers will do the best they can to always bracket the calls properly, I don't know if they ever guarantee it, and certainly when using custom view controllers you can find situations where these can be called multiple times.
In short, your -viewWillAppear:/-viewDidAppear: methods should be idempotent, meaning if -viewDidAppear: is called twice in a row on your controller, it should behave properly. If you want to load custom views, you may want to do that in -viewDidLoad instead and then simply put the on-screen (if they aren't already) in -viewDidAppear:.
You could also put a breakpoint in your -viewDidAppear: method to see why it's being called twice the first time it shows up.
maybe you invoke viewDidAppear in viewDidLoad (or some other stuff is going on there), since it's invoked only once during loading the view from the memory. It would match, that it's invoked two times only the first time.
This was not an iOS 5 bug, but a hidden behavior of addChildViewController:. I should file a radar for lack of documentation, I think
https://github.com/defagos/CoconutKit/issues/4
If you have a line like this in your AppDelegate
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
make sure you DON'T have a "Main nib file base name" property in your plist set to "Window.xib" or whatever your custom window nib is named. If you do, remove that row from your plist and make sure you something like
yourRootVC = [[UIViewController alloc] init];
[window setRootViewController:yourRootVC];
in your AppDelegate after instantiating your window. In most cases, you could then safely delete the Window.xib as well.
You definitely should provide more info.
Is this the root view controller?
Maybe you initiate the navigation controller with this root view controller and then push it to the navigation controller once again?
Another solution that may have been your underlying cause: Be sure you are not presenting any new view controllers from within your viewWillAppear: method.
I was calling:
[appDel.window.rootViewController presentViewController:login animated:YES completion:nil];
from within viewWillAppear and seeing my originating VC's viewDidAppear: method called twice successively with the same stack trace as you mention. And no intermediary call to viewDidDisappear:
Moving presentViewController: to the originating VC's viewDidAppear: method cleared up the double-call issue, and so now the flow is:
Original viewDidAppear: called
Call presentViewController here
Original viewDidDisappear: called
New view is presented and no longer gives me a warning about "unbalanced VC display"
Fixed with help from this answer: https://stackoverflow.com/a/13315360/1143123 while trying to resolve "Unbalanced calls to begin/end appearance transitions for ..."
it's such an annoying problem, you'd think it runs once but then I now found out about this which is causing mayhem... This applies to all 3 (ViewDidAppear, ViewDidLoad, and ViewWillAppear), I am getting this when integrating with a payment terminal; once it finish calling the API, the window is being re-loaded when it's already on-screen and all it's memory is still there (not retained).
I resolved it by doing the following to all the routines mentioned above, below is a sample to one of them:
BOOL viewDidLoadProcessed = false;
-(void)viewDidLoad:(BOOL)animated
{
if (!viewDidLoadProcessed)
{
viewDidLoadProcessed = YES;
.
.
.
... do stuff here...
.
.
}
}
Repeat the above for all the other two, this prevents it from running twice. This never occurred before Steve Jobs died !!!
Kind Regards
Heider Sati
Adding [super viewDidAppear:animated]; worked for me:
//Called twice
- (void)viewDidAppear:(BOOL)animated{
}
//Called once
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
}