UIViewController loadView method - iphone

when overriding the loadView method in UIViewController, should one call [super loadView] in the beginning of the method or at the end of the method? And why?

According to the UIViewController class reference, you should not call [super loadView] at all:
Your custom implementation of this method should not call super.

Normally you should not call loadView directly. It merely sets your self.view property and is called by the view controller only.
You should call [super loadView] only if you need the view created by your super class, because you want to include it in your decoration view hierarchy or something like that.

Just to be really sure, you didn't mean viewDidLoad, right? Because they are two very different methods... as of 3.0, the docs reccomend always calling viewDidLoad at the start.
You can call it either before or after, but usually it is placed at the end unless you have a reason to do otherwise.

Related

Custom initialise subview added from storyboard

I have a subclass of UIViewController that I want to add from the storyboard.
So I'm using what seems the standard methodology:
SubViewController *svc = [self.storyboard instantiateViewControllerWithIdentifier:#"SubViewControllerID"];
[self addChildViewController:svc];
[self.view addSubview:svc.view];
Which is fine but what if I want to call a custom init method on the subview?
I can do something like:
svc = [svc initWithFoo:#"Hello"];
Which seems to have to go after the addSubview call inorder for it to work.
Is this the best way to do this?
Seems a bit unorthodox. Calling an init method on an object that has already been created seems like its no longer truly an init method.
Maybe I should call it setWithFoo: or something and not have it return anything?
SubViewController *svc = [self.storyboard instantiateViewControllerWithIdentifier:#"SubViewControllerID"];
will cause the SubViewController to be inited with it's - (id)initWithCoder:(NSCoder *)decoder {} method.
Override that method (don't forget to call super)
If you want to do additional setup to your view controller after you instantiate it form the storyboard you can create some methods in the view controller's class and call them after the instantiate method fo the storyboard.
But be careful, if you try to make changes on any UI component in those methods, they wont be applied, and probably the app will crash. So use those methods to set params to the View Controller like array of objects, or any kind of data, and apply the UI changes for the view controller's view in viewDidLoad/viewWillAppear/viewDidAppear methods of your view controller.
Essentially I think the answer is that you can't use custom initialisers on ViewControllers added from the storyboard. Instead you have to set properties directly or through a method at the appropriate time in the life cycle as stated above.
Also as mentioned, the VC will be instantiated through initWithCoder, so calling an additional initialiser might be superfluous(?).
I encountered problems trying to use a custom initialiser that contains a call to super if I called it before the subview was added. I would just get a blank view added, I think because the superclass doesn't seem to know about the storyboard at that point. I had more success removing the call to super but that seems wrong.
This case would be more pertinent when adding subviews to a scrollview. For simplicity I left this out of my example.

removed nib issues and calling init

I have deleted my nib file from my UIViewController and now I want to make it so that it calls init instead of initWithNibName. However, even after I deleted my UIViewController, it is still calling the initWithNibName. What do I need to do to change this so that it calls init?
I initialized the rest of the UIViewController via code, in my UITabBarController I have the following:
- (void)viewDidLoad
{
[self setTabURLs:[NSArray arrayWithObjects:#"tt://mygroup",
#"tt://all",
#"tt://search",
nil]];
}
Three20 framework always calls initWithNib, even if the TTViewController is created without a nib file.
Just move your initialization code into the - (void)loadView function as you need to.
Why does it matter to you what init method is called? Just take the code you would put in init and put it in initWithNibName:bundle.
Find where UIViewController is being allocated and initialized and change it to init instead of initWithNib.

When overriding initWithCoder is it always necessary to call [super initWithCoder: coder]

In this code I am loading a View Controller (and associated View) from a .xib:
-(id)initWithCoder:(NSCoder *)coder
{
// add custom initialisation code here
[super initWithCoder:coder];
return self;
}
This successfully works, but I do not really understand what the line [super initWithCoder:coder] is accomplishing. Is that initializing my View Controller after my View has been initialized?
Please be as explicit as possible when explaining. Thanks.
Your class is a subclass of UIViewController. The call is telling your super class (UIViewController) to do the steps it needs to accomplish so that you can do your init steps. This would be setting up any properties that the UIViewController provides or registering for notifications that the UIViewController needs to do its work.
It is suggested almost every time you override a method from the super class to call the super class's method in addition to the steps you need to take.
Edit: Also if you don't need to do anything in a method the superclass provides, you can just leave it out and the super class's method will be used instead. In this case I would not provide the initWithCoder: method unless there was some code you need to preform in addition to what you showed.

Call a function in a UIViewController's UIView

I've created a view controller and the associated view using the interface builder. I'm trying to call a function that I added to the UIView from the UIViewController. I'm not sure how to call that function though.
I've tried
[self.view myFunction]
but that just makes my program crash.
Did you declare your IB outlets and connect the method to it?
Your view (more accurately nib)'s file owner should be set to your viewController class.
Unless your calling drawing functions and methods you shouldn't call anything on the view. You just don't need to.
Edit: grammar corrections.
How is the view getting initialized? Is it a custom view type? If your view is being initialized from a nib, make sure that the class on the view type is the class that has the method implemented.
It is probably crashing because UIView does not have a method named myFunction. In order to add myFunction to a UIView object, you need to subclass it.
I assume you have subclassed your UIView, and called it something like MyView. You also probably have subclassed your UIViewController and called it MyUIViewController. Therefore you may have:
#interface MyViewController : UIViewController {
MyView *myView;
....
}
Now you can call [self.myView myFunction];
That's one way. Another way may be:
[(MyView *)self.view myFunction];
This depends on whether myView is the first view in the hierarchy (or should be set up in your NIB files).

Who should call viewDidLoad on programmatically loaded views?

When I need to load a view programmatically I do the following:
MyController* myController = [[MyController alloc] init];
[[NSBundle mainBundle] loadNibNamed:#"myNib" owner:myController options:nil];
// use my controller here, eg. push it in the nav controller
This works fine, but my controller's viewDidLoad is never called. So I resorted to manually calling it after the loadNibNamed call, but it doesn't seem correct. I was expecting the framework to call the viewDidLoad on my behalf. Is this the right way or I'm missing something?
I am new to Stack Overflow, but I discovered this question and discovered a couple other methods to load a nib file that ensure that the viewDidLoad method gets called automatically. Ed Marty's answer is correct, but it requires you to go outside the ViewController's code to load the nib file, these two examples I offer here allow you to keep your code inside the ViewController's implementation. Not necessarily better ways, just different. If you know of any drawbacks to doing it this way, please let me know your thoughts.
First, inside the initWithNibName:bundle: method of your UIViewController subclass, you can replace the call:
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
with something like this: self = [super initWithNibName:#"NameOfAlternateNibFile" bundle:nibBundleOrNil];
Or, you can accomplish what appears to do exactly the same thing by the following:
[[NSBundle mainBundle] loadNibNamed:#"NameOfAlternateNibFile" owner:self options:nil];
[self setView:self.view]; //this line ensures that the viewDidLoad method is called
The key is in understanding what is written in the comments above the function definition for $initWithNibName:bundle: in the UIViewController.h file (included at the bottom of my answer here, see italics).
The nice thing about doing this using either of these methods is that viewDidLoad gets called in either scenario.
Here are the directives listed in UIViewController.h:
The designated initializer. If you
subclass UIViewController, you must
call the super implementation of this
method, even if you aren't using a
NIB. (As a convenience, the default
init method will do this for you, and
specify nil for both of this methods
arguments.) In the specified NIB, the
File's Owner proxy should have its
class set to your view controller
subclass, with the view outlet
connected to the main view. If you
invoke this method with a nil nib
name, then this class' -loadView
method will attempt to load a NIB
whose name is the same as your view
controller's class. If no such NIB in
fact exists then you must either
call -setView: before -view is
invoked, or override the -loadView method to set up your views programatically.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil;
You should load view controllers with
MyController* myController = [[MyController alloc] initWithNibName:#"myNib" bundle:nil];
Make sure your MyController extends from UIViewController, and the View property is set properly in Interface Builder.
The views are loaded lazyly by UIViewController. If you use the accessor myController.view in your code, the view should be loaded and viewDidLoad be called.
I noticed the same thing. I think ViewDidLoad must be called by the view CONTROLLER. Since you don't have a view controllr in your nib, you have to call the viewdidload manually. I"m having to do the same thing.