I want to setup a UIViewController within a NavigationController programmatically, however the loadView nor viewDidLoad method get called.
This is my code in the app delegate:
MyViewController *viewController = [[MyViewController alloc] init];
UIView *view = [[UIView alloc] initWithFrame:window.frame];
viewController.view = view;
UINavgationController *navController = [[UINavigationController alloc] initWithRootViewController:viewController];
[window addSubview:[navController view];
[window makeKeyAndVisible];
When I start the app I see a navigationbar, but no calls to loadView. What am I missing?
I thought loadView gets called after you call view
Edit
MyViewController *viewController = [[MyViewController alloc] init];
[viewController view]; // doesn't look right?
UINavgationController *navController = [[UINavigationController alloc] initWithRootViewController:viewController];
[window addSubview:[navController view];
[window makeKeyAndVisible];
edited towards Jonah's comment, but loadView still doesn't get called.
A UIViewController will create its view (by loading it from a nib or implementing -loadView) when the controller's view getter is called and its view is currently nil.
In the code shown you never invoke the view property's getter, only its setter.
Also, you are assigning the controller's view from your app delegate. UIViewControllers are expected to create their own views on demand, not have them provided by some other class. This approach will cause you problems later when you realize that the controller unloads its view and attempts to recreate it in response to memory warnings. Let your controller create its view, don't try to pass it one.
maybe you were not facing this issue... but the other day I ran into the same irritating trouble.. loadView, viewDidLoad and viewWillAppear not being called in my UIViewController.
My issue was v. simple but bit tricky to catch if you are not very careful. Instead of writing
-(void) loadView
I wrote:
-(void) loadview
Please note that this won't fire any warning. The difference of "V" and "v" in loadView can easily be missed. And obviously, since loadView didn't get called, viewDidLoad/viewWillAppear won't get called either as there was no view that got loaded (am not using any nib..creating the view programmatically).
-Anshu
Another gotcha worth noting is if you define a
#synthesize view;
without a matching #property in your implementation, this can result in calls to your view controller's returning nil, and no call to your loadView method.
Related
I'm pushing a UIViewController like so:
UIViewController* individualsController = [[[UIViewController alloc] initWithNibName:#"IndividualsController" bundle:nil] autorelease];
[self.navigationController pushViewController:individualsController animated:YES];
The NIB itself is loading fine, all the elements load on the screen. BUT none of the view controller's methods are getting called. No viewDidLoad, no viewWillAppear, just a pushed NIB with nothing else.
The view outlet is set up in the NIB; I can't figure out why none of it is getting called!
One possibility is that you are instantiating it as a UIViewController rather than the name of your UIViewController subclass, so it is calling those methods, but on UIViewController, not on your class. Assuming that the subclass is called IndividualsController, try changing the line to
IndividualsController* individualsController = [[[IndividualsController alloc] initWithNibName:#"IndividualsController" bundle:nil] autorelease];
and see what happens.
So I feel like a serious rookie right now, but I have a problem I can't seem to figure out. I have a barebones app, with literally nothing in it except a login screen and a second view containing a tableview. When I add the second view after logging in (I have done this like 4 times before...), the table view goes through its delegates and appears that it's going to load, but something happens. I have enabled my NSZombies, and it appears to be deallocating the new view, right before it appears.
After tracing through it, and building up again piece by piece, it appears to happen after I wire the table to the view as the datasource/delegate in IB. I have set the view as a UITableViewDelegate, and the methods indeed get fired. Does anyone have any idea what might be causing this behavior?
Have you added the 'second'view to an exisitng view using addSubview: or added it to some form of UINavigationController or UITabBarController? When you do this it will automatically increase the retain count and whatever code you have releasing the view won't cause is to be deallocated.
In my AppDelegate application:didFinishLaunchingWithOptions I have something like;
LoginViewController *login = [[LoginViewController alloc] init];
[login setDelegate:self];
loginNavController = [[UINavigationController alloc]
initWithRootViewController:login];
[window addSubview:[loginNavController view]];
And then once login has occured (and succeeded using a protocol/delegate to send the message back to AppDelegate) I call this code;
UIViewController *newView1 = [[UIViewController alloc] init];
UIViewController *newView2 = [[UIViewController alloc] init];
UIViewController *newView3 = [[UIViewController alloc] init];
myTabBarController = [[UITabBarController alloc] init];
myNavController = [[UINavigationController alloc]
initWithRootViewController:newView1];
// nav controller now retaining
[newView1 release];
NSArray *viewControllers = [NSArray arrayWithObjects:myNavController,
newView2,
newView3,
nil];
[myTabBarController setViewControllers:viewControllers animated:YES];
[[myTabBarController view] setFrame:[[UIScreen mainScreen] applicationFrame]];
[window addSubview:[tabBarController view]];
// tab bar controller now retaining
[newView2 release];
[newView3 release];
// remove login from application
[[loginNavController view] removeFromSuperview];
The AppDelegate has the following declared in the header file;
LoginViewController *loginViewController;
UITabBarController *myTabBarController;
UINavigationController *myNavController;
In the dealloc method for the AppDelegate these are released.
This gives me my login page and then when that has processed my views with a top nav all controlled using the bottom tab bar.
Hope this helps in some way.
You have either too many release (or autorelease) calls - or not enough retain calls - in your view loading/transitioning code, but it's impossible to be more specific without seeing that code.
What's probably happening is the autorelease pool is being flushed between your view loading and your view being shown, and that's what's leading the behaviour you describe.
I have the following code and I want to load the UIViewController. How can I initialize and load the UIViewController.
- (void) applicationDidFinishLaunching:(UIApplication*)application
{
CC_DIRECTOR_INIT();
NSLog(#"applicationDidFinishLaunching");
MainViewController *controller = [[MainViewController alloc] init];
}
From your delegate you can do this (assuming you have IBOutlet UIWindow *window):
[window addSubview:[controller view]];
[window makeKeyAndVisible];
Once a controller is loaded, you can push others (from the UIViewController):
controller = [[MainViewController alloc] init];
[[self navigationController] pushViewController:controller animated:YES];
Here is a link to the documentation for UINavigationController.pushViewController
http://developer.apple.com/library/ios/documentation/UIKit/Reference/UINavigationController_Class/Reference/Reference.html#//apple_ref/occ/instm/UINavigationController/pushViewController:animated:
TestViewController *testController = [[TestViewController alloc] init];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[self.window setRootViewController:testController];
[self.window makeKeyAndVisible];
Although adding a subview will work fine, you will receive the following warning unless you set your controller as RootViewController:
Application windows are expected to have a root view controller at the
end of application launch
Are you using a nib file to set up the user interface of your view? The code you currently have does load and initialize the ViewController. But you would then need to add some user interface elements to your view, and present that view controller in your application. If you arre using a nib file for your user interface, then you want:
MainViewController *controller = [[MainViewController alloc] initWithNibName:#"nibFileName" bundle:nil];
This will associate your controller with the nib file. If you are not using a nib file, you need to programmatically add each element that you wish to display.
After your view is set up, you then need to present the view controller, by either adding it as a subview to your current view, or using a navigationController to push the new viewController. You need to be more specific about exactly what you are trying to do.
I think what you want to add is:
[[NSBundle mainBundle] loadNibNamed:#"nibWithMainViewControllerAsOwner" owner:controller options:nil];
loadNibNamed:owner:options: is the only method added to NSBundle by UIKit. See NSBundle UIKit Additions Reference. And if there's any problem with outlets not being wired up correctly then check all your outlets are key-value coding compliant (alternative answer: make sure they're correctly exposed as properties).
[viewController view]
That's how to load viewController. When the view is accessed it's lazy loaded.
I am a newbie iPhone Programmer and have a question regarding how to access methods of a Parent View Controller.
In my program when the program first loads (applicationDidFinishLaunching) I do the following code:
[window addSubview:rootViewController.view];
[window makeKeyAndVisible];
which basically calls this
- (void)viewDidLoad {
HomeViewController *homeController=[[HomeViewController alloc] initWithNibName:#"HomeView" bundle:nil];
self.homeViewController=homeController;
[self.view insertSubview:homeController.view atIndex:0];
[homeController release];
[super viewDidLoad];
}
Now, I have an IBAction call on HomeViewController that I want to have it call a method in root View Controller
I want to call this method
- (void)loadNewGame
{
self.questionViewController = [[QuestionViewController alloc] initWithNibName:#"QuestionView" bundle:nil];
//[homeViewController.view removeFromSuperview];
[self.view insertSubview:questionViewController.view atIndex:0];
}
So my question is how do I call a method from the Parent View controller?
I've tried
[self.view removeFromSuperview];
[self.parentViewController loadNewGame];
but that doesn't seem to work. Could someone please ploint me in the right direction.
Thanks in advance
Scott
First off, typically you call [super viewDidLoad] first in your viewDidLoad.
You will have to have an instance variable in your homeController class for your rootViewController. Then you could have a method in homeController:
- (void) loadNewGame
{
[self.rootViewController loadNewGame];
}
This is one of many different ways to accomplish this. You may want to move the method to homeController completely. Or you may wish to have IB use the rootViewControllers' methods directly...
Here is another discussion of this.
First off your code doesn't really make sense. Why are you adding your HomeViewController in a -viewDidLoad call. If you want to load the HomeViewController as the initial view, you should set that in Interface Builder instead of RootViewController. When you want to display a new view controller, you should be using a navigation controller stack and pushing the new view controller onto it with [[self navigationController] pushViewController:newViewController animated:YES].
Assuming you get that sorted, you should create a delegate (id) field for your child view controller that you can set when you instantiate the new view controller. So your code might look something like this:
HomeViewController *homeController=[[HomeViewController alloc]
initWithNibName:#"HomeView" bundle:nil];
[homeController setDelegate:self];
[[self navigationController] pushViewController:homeController animated:YES];
[homeController release];
Then, when your action gets fired in the HomeViewController, you can check to see if the delegate is set and if so, call the selector in question, like this:
- (IBAction)action:(id)sender;
{
if (delegate && [delegate respondsToSelector:#selector(loadNewGame)])
[delegate performSelector:#selector(loadNewGame)];
}
You might want to read Apple's docs on how to use the navigation controller stack. This might help clarify some things.
I ran into a situation that seems to suggest otherwise. In the following code snippet, if I remove the line: self.navigationController = nav, the root controller's view won't show up, suggesting to me that addSubview might not actually retain the view as otherwise suggested. Any idea?
- (void)applicationDidFinishLaunching:(UIApplication *)application {
self.testViewController = [[TestViewController alloc] initWithNibName:#"TestView" bundle: [NSBundle mainBundle]];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:self.testViewController];
self.navigationController = nav; //<-- if this line is removed, test view won't show up
[window addSubview:nav.view];
[nav release];
}
This line:
[window addSubview:nav.view];
does NOT add a view to the screen immediately. It is displayed by the OS in some future run loop on a possibly different thread. The actual implementation we can't be sure of.
This is why Apple defines delegate methods like viewDidAppear/viewWillAppear, otherwise we would not need them as we would know precisely when these events occur.
Moreover, adding a subview as you said, does indeed retains the view. It does NOT however retain the view controller or the navigation controller. Since the navigation controller WILL retain any added view controllers, we do not have to back them with an ivar.
But, your reference to the navigation controller must persist beyond the scope of the method. or depending on your code it could be dealloc-ed or have its reference lost.
So you must keep a reference to the navigation controller with an ivar and set it like so:
self.navigationController = nav;
So even though nav.view contains a pointer to testViewController.view, the application has no reference the navigation controller and, by extension, the view. The result is a blank screen.
To make this more obvious that it isn't a retain/release problem, you are actually leaking in the following method:
self.testViewController = [[TestViewController alloc] initWithNibName:#"TestView" bundle: [NSBundle mainBundle]];
You need to autorelease to balance out your retain/releases by:
self.testViewController = [[[TestViewController alloc] initWithNibName:#"TestView" bundle: [NSBundle mainBundle]] autorelease];
So, that means your view has never, ever been deallocated any time you have ran this code. Which further assures us that your issue is indeed a lost reference.
The problem probably isn't that the view isn't retained, it's that the controller isn't retained.
Without this line:
self.navigationController = nav
Nothing is retaining the navigation controller. It would be strange to have the view outlive the controller.
This doesn't look lika a retain/release question to me. You view won't show up if you comment out self.navigationController = nav; because then in the next line, [window addSubview:self.navigationController.view] your self.navigationController property won't be set. It's probably nil or it would crash but can't say for sure without more of the code.