the Benifits of awakeFromNib? - ios

I've been learning coredata by making a lot of simple test apps based on the xcode Navigation controller template with "use coredata" checked.
The awakeFromNib method in the App delegate has been a source of problems for me, because I'm adding other views to the controller and changing the load sequence, so that RootViewController may be a second or third choice.
I've figured out what awakeFromNib is doing, and I've removed it so the app delegate is no longer tied to any particular view. (So when I do want to load RootViewController, I'll load it as a regular view, and use its own viewDidLoad to initialize the managedObjectContext for the view).
My question: are there performance gains or other benefits by using awakeFromNIb in the AppDelegate? or is it just another way of doing the same thing as I'm doing from the viewDidLoad method?

All the methods fire at different times and different circumstances.
awakeFromNib is called when the nib file associated with a class is loaded from disk. Any class that can own a nib can use it. viewDidLoad is used only by view controllers. It is usually called when loading from nib as well but it can also be called by a view created in memory (very rare circumstance.)
In either case, you only put functionality in either that you only want to run once when the instance is first loaded. E.g. a common nubie mistake is to put code in viewDidLoad that needs to run every time the view appears. Say as with master view that opens a detail view and then reappears when the detail view is dismissed. If the code for the master view is in viewDidLoad it will only run the first time the master view is loaded but not any of the subsequent times the master view disappears and reappears.
You generally don't initialize any other views or do much of anything in the app delegate's awake from nib. That is usually performed in applicationDidFinishLaunching.

Related

Why does Apple recommend us to not invoke viewWillLoad, viewWillAppear, viewDidDisappear, etc.?

I'm following an exercise from a book and we're building out the view controllers programmatically and creating unit tests. The book also says this, and from previous experience with reading Apple reference docs, Apple references always say to not invoke viewDidLoad, viewWillAppear, viewDidDisappear, etc directly. I'm curious to know why this is and what happens if we do?
viewDidLoad, viewWillAppear, viewDidDisappear and so on are the runtime's way of letting you know that certain important things are happening:
viewDidLoad, the view controller has just obtained its view
viewWillAppear, the view controller's view is about to be placed into the interface
viewDidDisappear, the view controller's view is about to be removed from the interface
These are events that the runtime is responsible for, and it sends you messages to let you know they are happening so that you can respond, if you wish, at the appropriate moment.
It would make no sense for you to call them, because you do not know when these things are happening (except insofar as the runtime calls them)! If you called them at some arbitrary moment, you would be lying, e.g. saying that the view has just loaded when in fact it has not just loaded, and so you would break your own code or worse.

self.navigationController is nil during state restoration

After implementing state restoration in my app I am having difficulty with my view controllers.
My issue is that in viewDidLoad of the view controller I am attempting to restore the self.naigationController property, which is nil.
I have set breakpoints in the viewDidLoad method of each view controller that comes before the one I am trying to restore. In the first view controller, the navigation controller is found. In every one after that, including the one I am trying to restore, the navigation controller is nil.
This is causing bugs where I cannot set the navigation bar visibility, views are misplaced, etc.
Does anyone have an idea why this might be?
Try moving the code to viewWillAppear.
Unlike viewDidLoad, viewWillAppear can get called multiple times, so take care to make sure your code is idempotent. That is, make sure the results are what you expect if the method is called repeatedly. For example, make sure you don't initialize a new subview if the view has already been added.
The navigationController property searches up the parentViewControllers to find one of class UINavigationController. Only view controllers loaded from the storyboard can find their navigation controller at the viewDidLoad time (and in awakeFromNib). It is likely you are instantiating a new instance of the view controller during the restore process rather than using the one that was created by the storyboard. The solution is either to help the restore process find the existing view controller if it has changed paths e.g. because of split controller orientation change (via viewControllerForRestorationPathComponents in your app delegate) although that comes with its own set of issues, or make your view controller work by not requiring the nav controller in the viewDidLoad, e.g. put it in the viewWillAppear as others have suggested.

UIViewController - where to put init of instance variables (using Storyboards)

I'm using Storyboards. I need to init instance variables of UIViewController just once. viewDidLoad and awakeFromNib fire each time I open a viewController from menu (I'm using SWRevealViewController for sidebar menu as in Facebook app). Is it normal for awakeFromNib to fire many times or is it SWRevealViewController bug?
So is there some special init method or do I need to set instance variables from outside of viewController (in AppDelegate?)
EDIT:
I found this question
SWRevealViewControllerSegue, reusing Viewcontrollers
I didn't realize that each time you show a controller via segue it creates a new instance of controller. So what does it mean? Does it mean that if I have a table of data loaded from web API - it will be reloaded each time I go back and forth through segue?.. Doesn't seem very effective to me. Is it normal for iOS?
View controllers are either recreated or reused depending on the situation. When you push a view controller onto a navigation controller's stack, you almost always push a new instance. When using a tab bar controller, the view controllers it contains are often held in memory. To avoid excessive memory consumption, it makes sense that view controllers are cleaned up when possible, rather than held around.
In the case of your SWRevealViewController then yes, it sounds as though your view controller should be recreated every time. You ideally shouldn't be directly loading any data from a web API within your view controller; instead, extract your API calls and models into separate classes that you can reuse from any view controller. Then, rather than reloading the data over the network when your view controller loads, you just need to fetch the latest data from your model / store class.

How to instantiate a particular view controller with storyboard in iOS at early stage of loading?

When using tabs with storyboard in iOS 5, some of them may take quite a long time to initialize when switching to it (for example, a tab containing GLKViewController).
This happens because an amount of work in viewDidLoad method in this controller could be very big.
Is there a way to initialize particular view controller (and call it's viewDidLoad method) defined in the storyboard at early stage - when an application starts? Having done this, the delay should be eliminated.
Are you sure it's the view controller's instantiation and not the viewDidLoad method? The view controllers are probably all created when the storyboard is unpacked, but a view controller tries to delay loading its actual view object as long as possible; viewDidLoad isn't called until the view property of your UIViewController subclass is accessed.
So a way around this could be to manually access the view property:
__unused CGRect frame = [[tabBarController.viewControllers objectAtIndex:index] view].frame;
If the slowdown is, in fact, in the instantiation and the view controller isn't being created until you switch to that tab, then you'll have do force the view controller to be instantiated by accessing it programmatically, like in the above example.
Calling the frame of the vewcontroller or the .view property will most likely work,
but i dont advice you to mess up with the viewcontroller initializations and view settings
For the following reasons
changes you make will not be standard, they will be tricks and hacks that will later on get out of hand
changes that you make will not be carried with you easily to other projects you create
If i faced a problem like this i would create the GLKViewController separately for example in the app delegate and held it there, untill the viewDidLoad gets called in the viewController, then i would move this initilized GLKViewController to the viewController

Setting up UIViewController before pushing/presenting it

In my app, I use a UINavigationController to switch between many different UIViewControllers. The only problem is that with one of my views, upon it loading, I have to do lots of customization (both data access and graphics, both of which must be done in code). When the view controller is pushed, the animation is extremely choppy, because the phone is forced to both animate the transition and set up the view at the same time.
Setting up the view after it is loaded is not an option, so is it possible to set it up (there is a method called setupViewDidLoad that has all of the necessary code in it) during allocation before it is pushed/presented?
Edit:
Let me modify my question slightly. I have found that if I present the view controller using [self presentModalViewController:animated:] instead of pushing it with the navigation controller, there is no choppiness. What is the reason for this?
Your best bet is to do this. Set up any code you need in viewWillAppear in your views .m file. If you have to access data remotely you may want to think about creating a data storage class of its own to handle and store that so it can do it whenever - even if the view isn't loaded or hasn't been loaded yet.

Resources