Re: Initializing a view controller...
Re: Initializing a view controller...
- Subject: Re: Initializing a view controller...
- From: Andreas Grosam <email@hidden>
- Date: Mon, 10 Jan 2011 18:58:25 +0100
On Jan 10, 2011, at 4:17 PM, Phil Hystad wrote:
> Is there a proper way to initialize a view controller. So far, I have been doing this in the application delegate by calling calling an initialize method ( i.e. [viewController initialize]) in application:didFinishLaunchingWithOptions: method (prior to the view being added to the window and the window made visible).
*** Important ***
+(void)initialize is a class method which the runtime sends to the class exactly once just before any of this class' method is invoked, and any of its super class if +initialized has not yet been invoked.
You rarely need to override +initialize -- and you never call it yourself!
But yes, there is a proper way to do initialization of a view controller object :) There are lots of examples of how you should do this within the iOS or Mac OS X documentation.
Basically, when you load your view from a nib you will override these methods in order to initialize a view controller:
-viewDidLoad
This method is called regardless of whether the views were stored in a nib file or created
programmatically. You usually override it to do additional setup after the view has been
loaded from a nib.
If you override -viewDidLoad you may want to override -viewDidUnload accordingly, which is the "counterpart" of -viewDidLoad.
-awakeFormNib
To do additional setup after the view has been loaded from a nib. You often can do all your setup
in viewDidLoad, but sometimes this seems a better place. At the time the method is invoked,
outlet and action connections are already established.
In the cases where you want to create the controller's view yourself programmatically, you have to use
-loadView. If you do so, you need to create the view hierarchy and assign the root view to the view property of the controller.
You must not call any of these methods yourself! The framework will do this for you when it is appropriate.
An example might be useful:
The following code assumes you have a nib where you load the view:
@interface MyViewController : UIViewController {
IBOutlet UIView* mySpecialSubView;
NSArray* myArray;
}
@property (retain) UIView* mySpecialSubView;
@property (retain) NSArray* myArray;
@end
@implementation
@synthesize mySpecialSubView;
@synthesize myArray;
- (void) viewDidLoad
{
[super viewDidLoad]; // always invoke super!
// In debug mode, you might check here whether you have established the links for your outlets in IB:
NSAssert(mySpecialSubView, @"IBOutlet 'mySpecialSubView' is nil"); // forgot to setup the link in IB?
// configure my view unless this is already done in IB:
self.view.backgroundColor = [UIColor blackColor];
// do other setup, for instance setting up a navigation bar, navigation item
...
// if your view controller needs to initialize other ivars, you might initialize them here,
// or do "lazy initialization" (see below)
...
// Note, that viewDidLoad will be called *everytime* the view gets reloaded from
// the resource!
// Sometimes, you explicitly DON'T want to perform certain initialization steps again
// after the view will be reloaded. In this case, use a flag as an ivar which determines
// whether you have done these initialization steps:
if (!isInitialized) {
[self setupOnce];
isInitialized = YES; // this is an ivar
}
}
You have to override -viewDidUnload in certain cases, e.g.:
- (void) viewDidUnload {
self.mySpecialSubView = nil; // Outlets shall be set to nil!
// optionally, you might want to release myArray - just in order to safe memory. But
// this depends on your needs, and often you explicitly don't want the array to be
// recreated after a reload of the view.
self.myArray = nil; // optionally
}
// lazy initialization - this overrides the getter method which was otherwise defined
// by the @synthesize directive:
- (NSArray*) myArray {
if (myArray == nil) {
myArray = [NSArray alloc] init... ];
}
return myArray;
}
// don't forget to release ivars if required:
-(void) dealloc {
[mySpecialSubView release], mySpecialSubView = nil;
[myArray release], myArray = nil;
[super dealloc]; // always invoke super (at the last statement)
}
One thing you should care of:
-viewDidLoad and -awakeFormNib, as well as -loadView may be called more than once for the lifetime of the view controller. So, be carefully not to initialize ivars in such a way that you get a memory leak. The following code snippet would be the wrong way:
- (void) viewDidLoad {
[super viewDidLoad];
myArray = [[NSArray alloc] init...]; // possibly memory leak!
}
The way to do proper initialization would leverage properties:
- (void) viewDidLoad {
[super viewDidLoad];
NSArray* tmp = [[NSArray alloc] init...];
self.myArray = tmp; // property retains
[tmp release], tmp = nil;
}
However, when the view is reloaded (once it has been unloaded for some reason), the array will be initialized again! This may or may not have undesired side effects since the array will be released and initialized again. So, lazy initialization may be the preferred way for certain ivars.
Regards,
Andreas
>
> However, I am not sure if this is the Cocoa canonical way of doing things. By the way, this example comes from UIKit but the same question would apply to any OS X Cocoa application too.
>
> phil
> email@hidden
>
> _______________________________________________
>
> Cocoa-dev mailing list (email@hidden)
>
> Please do not post admin requests or moderator comments to the list.
> Contact the moderators at cocoa-dev-admins(at)lists.apple.com
>
> Help/Unsubscribe/Update your Subscription:
>
> This email sent to email@hidden
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden