What is the difference between loadView and viewDidLoad? - iphone

I know there is a seemingly exact duplicate of this question here: iPhone SDK: what is the difference between loadView and viewDidLoad?
However, I have read that question and still it was not fully answered.
I'm not using IB as the UI is dynamic.
So should I create the self.view and then add the subviews in loadView,
or should I create the self.view in loadView and add the subviews in viewDidLoad?

When you load your view from a NIB and want to perform further customization after launch, use viewDidLoad.
If you want to create your view programatically (not using Interface Builder), use loadView.

For your specific question, you should add the subview in viewDidLoad. Because, if you overwrite the loadView, you have to do all the jobs, loading all the views.
Here is the explanation from Apple's documentation:
The steps that occur during the load cycle are as follows:
1.
* Some part of your application asks for the view in the view
controller’s view property.
2.
* If the view is not currently in memory, the view controller calls its loadView
method.
3.
* The loadView method does one of the following:
If you override this method, your implementation is
responsible for creating all
necessary views and assigning a
non-nil value to the view property.
If you do not override this method, the default implementation uses
the nibName and nibBundle properties of the view controller to try to load the view
from the specified nib file. If the
specified nib file is not found, it
looks for a nib file whose name
matches the name of the view
controller class and loads that file.
If no nib file is available, the method creates an empty UIView object
and assigns it to the view property.
4.
* The view controller calls its viewDidLoad method to perform any
additional load-time tasks.

It is very simple actually. If you do it without IB, then your UIViewController's view property is empty. So set it at loadView!
I only do setting of view at loadView and nothing else.
Other than that, do all thing inside viewDidLoad. Here is some example:
- (void)loadView {
CGRect frame = [[UIScreen mainScreen] applicationFrame];
baseView = [[UIView alloc] initWithFrame:frame];
[self setView:baseView];
[baseView release];
}
That's it! I am done. And would never want to add more to it. Then at the viewDidLoad, I add all those subviews I want to.
- (void)viewDidLoad {
[super viewDidLoad];
msg = [[UILabel alloc] initWithFrame:CGRectMake(0, 200, 320, 50)];
[msg setText:#"Your profile is empty!"];
[[self view] addSubview:msg]; // hey, I have done my view at loadView, so I have it now
[msg release];
}
I could be wrong in my understanding :)

loadView is the method that actually sets up your view (sets up all the outlets, including self.view).
viewDidLoad you can figure out by its name. It's a delegate method called after the view has been loaded (all the outlets have been set) that just notifies the controller that it can now start using the outlets.
viewDidLoad:
"This method is called after the view controller has loaded its associated views into memory. This method is called regardless of whether the views were stored in a nib file or created programmatically in the loadView method."
loadView:
"If you create your views manually, you must override this method and use it to create your views."

Add subviews in viewDidLoad. That way you are 100% sure than the view did indeed load and is ready for consumption.

Use viewDidLoad for initialize views and constrols. And use loadView if you don't have Nib/Xib and would like your ViewController has custom (not UIView) view.

Only use loadView when you want to create a view yourself.
Don't use loadView after you use interface builder or init with nib since these actions have already called loadView in the underly implementation.
Also, when use loadView, assign view first before doing any other settings:
-(void)loadView {
[super loadView];
// if you do any things here before assigning a view
// it will try to get a view first by calling loadView()
// and ends up with a crash since a dead loop.
self.view = ...;//assign your view here
//do other settings
}

Related

Calling a single view in different UIViewControllers

I have declared a UIView inside a UIViewController class. Can I call this UIView in another UIViewController class?
If its possible how can I call it?
Yes, you can use a single instance of a view in a number of views/viewControllers. Typically I do the same with Views that carry advertisements.
You pass them along as you would do with any other object.
If you do not create it in Interface Bulder (I suggest creating it programmatically) then you may want to define it within your application delegate rather than a view controller and pass it to the individual view controllers that make use of it.
Within the view controller just add it as sub view accordingly, as you would do it with any other view too.
There is one thing though. When you add this view to another super view for the second time or more then it will be removed from its prior super view. That means that you will have to add it as super view again, when its prior super view becomes visible again. A view can only be part of one view hierarchy at a time.
Sample code, thanks to Gordon:
/* Untested and simplified */
AppDelegate.h:
#property ( strong, nonatomic) ReuseableView reuseableView
;
AppDelegate.m
#synthesize reuseableView;
/* in didFinishLaunchingWithOptions ...*/
reuseableView = [[alloc] init]; // or init from nib, initwithframe, etc.
viewController.m
/* In each view controller that uses the view */
- (void) viewWillAppear:(BOOL)animated
{
[self.view addSubview:((AppDelegate*)[UIApplication sharedApplication].delegate).reuseableView];
}
- (void) viewWillDisappear:(BOOL)animated
{
[((AppDelegate*)[UIApplication sharedApplication].delegate).ReuseableView removeFromSuperview];
}
I am not quite sure whether this removeFromSuperview is really required. The next addSubview will remove it from its existing superview anyway and if addSubview is called on the same super view twice in a row then it does not do any harm. However, it is save using removeFromSuperview at this point.
Well, summarized that is basically it. You define, create and store your shared view (the reusableView in Gordon's example) at a common place. The application delegate is a good place for that. In each view's controller that uses the shared view you fetch it from the delegate and add it as subview to the current view.
I would subclass UIView and import it on the ViewControllers where I wanna use it
NSArray *nibArray = [[NSBundle mainBundle] loadNibNamed:#"YourView" owner:self options:nil];
yourView = (YourView *)[nibArray objectAtIndex:0];
Then you set its frame and [self.view addSubview:yourView]

UIViewController and XIB question

How do I prevent a UIVIewController from loading the xib?
I downloaded an XCode (iPhone) project online, and I want to stop the xib file from loading. The view did load method doesn't have any code in it which deals with xib. How do I force the UIViewController to be loaded from it's viewDidLoad method instead of the xib?
Overwrite loadview but DO NOT call [super loadview]. Example:
-(void)loadView{
self.view = [UIView new];
[self.view setBackgroundColor:[UIColor redColor]];
}
From the Documentation
loadView
Creates the view that the controller manages.
You should never call this method
directly. The view controller calls this method when the view property
is requested but is currently nil. If you create your views manually,
you must override this method and use it to create your views. If you
use Interface Builder to create your views and initialize the view
controller—that is, you initialize the view using the
initWithNibName:bundle: method, set the nibName and nibBundle
properties directly, or create both your views and view controller in
Interface Builder—then you must not override this method.
The default implementation of this method looks for valid nib
information and uses that information to load the associated nib file.
If no nib information is specified, the default implementation creates
a plain UIView object and makes it the main view.
If you override this method in order to create your views manually,
you should do so and assign the root view of your hierarchy to the
view property. (The views you create should be unique instances and
should not be shared with any other view controller object.) Your
custom implementation of this method should not call super.
If you want to perform any additional initialization of your views, do
so in the viewDidLoad method. In iOS 3.0 and later, you should also
override the viewDidUnload method to release any references to the
view or its contents.
Write your own init method. Later if you require the nib you can create a UINib object and when you need the view you can use instantiateWithOwner.
Using init when creating your view controller will prevent the nib loading. Another thing to do is to name the nib something other than the name of the view controller - because the nib can be loaded automatically if they match. I use ViewControllerName_iPad or ViewControllerName_iPhone and create the view required depending on device idiom.
The code to load from the xib file is not in the viewDidLoad method of the view controller itself.
You should usually find it in the application delegate's didFinishLaunchingWithOptions: method, or in the info.plist file, under the NSMainNibFile entry.
Try changing the initWithNibNameOrNil method to just init.
If that doesn't work, also override the loadView method by uncommenting it and setting your view there.
Here's an example:
- (id)init
{
self = [super init];
if (self) {
// Custom initialization
}
return self;
}
- (void)loadView {
[super loadView];
UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0,0,320,460)];
myView.backgroundColor = [UIColor redColor];
self.view = myView;
[myView release];
}
Perhaps I'm barking up the wrong tree here, but is the UIViewController loading its view from a XIB because the XIB that loads the UIViewController itself has a "NIB Name" set in the view controller's settings?
e.g. load up MainWindow.xib, see your view controller. Select it, then look in the view controller settings over on the right (4th tab). One of the settings is "NIB Name". Just make that blank to stop the view controller loading its view from that XIB/NIB.

viewDidLoad(), LoadView() [duplicate]

This question already has answers here:
iPhone SDK: what is the difference between loadView and viewDidLoad?
(8 answers)
Closed 9 years ago.
What is the difference between viewDidLoad() and LoadView()? In what way are they different from each other?
Which one is better when we develop applications without using XIB ?
Thanks .
ViewDidLoad is called when your view loading is finished and loadView is called when loading starts.
And when you make a new project you see comments on these methods which clearly gives a tip when you should use which function
see this
/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
}
*/
/*
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
}
*/
These comments are clear and easy to understand.
viewDidLoad()
is to be used when you load your view from a NIB and want to perform any customization after launch.
LoadView()
is to be used when you want to create your view programmatically (without the use of Interface Builder).
If you intend to use IB to build your UI, you should do all your post IB initialization in viewDidLoad. The class will not call loadView at all if you use a nib to initialize a controller.
If you initialize the controller in code, the viewController will call loadView first, then viewDidLoad. You can do all your initialization in loadView, or viewDidLoad, depending on your preferences.
However, if you decide to use loadView, be sure to set the view property before attempting to read self.view, otherwise you will enter into an infinite loop and crash.
If you initialize your view from stroyboard or xib file, don't override this method or call [super loadView] inside.
if you call [super loadView] inside the method, you better never override this method and put the following code to your viewDidLoad method.
if you initialize your view programmatically, you should NEVER call [super loadView]. and You must assign your rootView to self.view property, or you may get a perfect crash.
Isn't it obvious?
viewDidLoad is called... When the view finishes loading.
loadView is called when the view is told to load.
Neither is better or worse. It's all dependent on your design.
Good luck :)
view controller loads its view from nib associated with it if there is no nib associated, then it automatically called it's loadView() method to fill it's View.
In that case you need to implement loadView() method.
by default it returns nil
when your view loads in to the memory viewDidLoad() method is called here you can do your custom initialization according to your requirement.
If you are developing applications without using xib LoadView() method is called and if there is an xib then ViewDidLoad method is called
So it is better to use LoadView method.

How to update or reset a UIView with a custom subview?

I have a UIView in a UIViewController to which I add a custom subview in the viewDidAppear method.
MyView *myView = [[MyView alloc] initWithLabelText:text];
[self.view addSubview:myView];
[myView release];
The text variable is a string used on a label in myView. This text changes every time you come back to the current view. But it seems that viewDidAppear does not reload the view - it rather loads a new view over the old one - so I have two labels over each other.
I tried to use viewWillAppear but it doesn't make any difference. I also tried to use [self.view setNeedsDisplay] - doesn't help. I also tried to make myView an instance variable, but it also didn't help.
What worked was to remove the view explicitly, when I declared it as an instance variable:
- (void)viewDidDisappear:(BOOL)animated
{
[_myView removeFromSuperview];
}
Although there is this workaround I would like to simply reset the view when getting back to it. Does anybody know how to do that? I would appreciate it ;)
Don't alloc and init the custom subview every time, only the first time viewDidAppear is called. Then retain it in a property for subsequent use.
The followings thing can ben considered.
viewDidLoad --> alloc and init your sub views
viewDidAppear --> update sub views
dealloc --> release sub views.

Using a custom UIView from multiple view controllers

I have created a custom UIView that I would like to use on multiple different view controllers in my iPhone application. Currently, I have copied the UIView that contains the controls from the nib file for the first view controller, pasted it into the other view controllers, and then wired up all of the actions to each view controller. This works fine, but is not the optimal way that I would like to use this custom view.
My custom view is reasonably simple, it consists of some UIButtons with labels, and tapping on these buttons fires actions that changes the contents of controls on my view controller's view.
What would be a strategy to consolidate the definition and usage of this UIView? Ideally, I would like to just reference this custom view from the nib of view controllers, and have my view controller respond to actions from this custom view.
EDIT: OK, based on J.Biard's suggestions, I have tried the following with not much luck.
I created another UIView based nib file with the contents (for now just some UIButton objects) of my reusable view and UIView subclass .m and .h files, and then set the nib File's Owner class to my newly created class name.
Then, I added most of the code from J.Biard (I changed the rect to 50,50,100,100, left out the setDelegate out for now, as I am just trying to get it working visually for now, and i found that [self.view addSubview:view] worked much better than [self addSubView:view]) to the end of the viewDidLoad method of the first view controller that is displayed when the app fires up.
And what I get now is my main view with a black square in it. Have I missed an outlet somewhere, or is there some initialization needed in initWithFrame or drawRect in the UIView subclass?
Create your MyCustomView class and nib file.
In the nib file, set Files Owner to MyCustomView - then design your view as normal, with a top level UIView. Create an IBOutlet in MyCustomView to link to your top level UIView in your nib file.
In MyCustomView add this method:
- (BOOL) loadMyNibFile {
if (![[NSBundle mainBundle] loadNibNamed:#"MyCustomView" owner:self options:nil]) {
return NO;
}
return YES;
}
In your view controllers you can use this custom view like so
- (void)viewDidLoad {
MyCustomView *customView = [[MyCustomView alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
[customView loadMyNibFile];
[self.view addSubview:customView.view]; //customView.view is the IBOutlet you created
[customView release];
}
You could also create a convenience class method on MyCustomView to do this if you liked.
If it is very simple I would recommend that you create a subclass of UIView in code and create instances of this class (or you can use Interface Builder to create the custom UIView that is then archived into the NIB file and restored later on also using code).
Using the code solution you could create instances of your custom UIView in your controller by calling something like:
#import "MyCustomView.h"
// let the superview decide how big it should be or set it as needed.
CGRect sizeRect = CGRectMake(0,0,0,0);
// create an instance of your view
MyCustomView *view = [MyCustomView alloc] initWithFrame:sizeRect];
// set a custom delegate on the view or set callback methods using #selector()...
[view setDelegate:self]; // self = view controller
// add the view to the controller somewhere... (eg: update CGRect above as needed)
[self addSubView:view];
// don't forget to release the view somewhere ;-)
This example assumes that you create a delegate protocol that your View Controller can respond to or you can wire up events dynamically using #selector. If you don't want to create instances of the view in code you could add a "UIView" to your NIB file and set it's class type in the inspector window (command -> 4 -> class dropdown).
If you want to do everything in interface builder you can create your custom UIView and use something like "- (NSArray *)loadNibNamed:(NSString *)name owner:(id)owner options:(NSDictionary *)options" (see NSBundle) to load the NIB file dynamically. This presents it's own challenges though it is also feasible.
The most involved option would be to create your own xcode custom UI library / plugin so that your custom control / view could be dragged into each NIB file from the Library window like any other control shipped by Apple.
Hope this clarifies or eliminates some options for re-using controls for you.
Cheers-