How to load a UIViewController programmatically? - iphone

I'm trying to load a UIViewController from code. I basically created a UIViewController generating a .xib file. I load it with the following code:
testViewController = [[TestViewController alloc] initWithNibName:#"TestViewController" bundle:nil];
this works but apparently (from what I have read) only the view is kept and the controller is deallocated (something which I have tested putting a breakpoint in the UIViewController's dealloc method). I need to keep the UIViewController or otherwise, create a UIViewController with a UIView loaded from a nib file. How can this be achieved?

Not sure what you mean. What you're doing there is correct. Since you've allocated it, you also -need to send a release statement to the view controller at some point, till then it shouldn't be dealloc'ed.
A view might get released and set to nil under a special case where the application receives a memory warning, but I'm not sure if this was what you've read.

Related

i don't know why this table view code crashes

hello i'm studying iOS programming
i created a project, which is an empty application
and i created table view controller without xib file.
and i inserted follow code in didFinishLaunchingWithOptions
TableViewController *tvc = [[TableViewController alloc] init];
[self.window addSubView:tvc.view];
[tvc release];
this code was crashed when i scrolled down. why is that?
when i comment this code
[tvc release];
program doesn't crash.
i didn't write dealloc in AppDelegate file.
why is that??
i think i created table view controller with alloc
so retain count is 1.
and add sub view to window and table view controller retain count is 2.
so i release table view controller
but it crash when i scrolled down.
i don't know why..
help me please
Simple, adding tvc.view as a subview of the window causes tvc.view to be retained but does not retain tvc itself. In essence, your TableViewController instance becomes invalid as soon as you call release on it. The app crashes when you scroll presumably because the TableViewController instance is configured as a delegate or datasource for a UITableView or UIScrollView or any other thing associated with tvc.view.
Also note that the way you are displaying the view is not the recommended way to go about it. Really you should be calling presentModalViewController: or pushViewController: and passing the TableViewController instance. This will cause the TableViewController to be retained until it is dismissed/popped, making it safe for you to call release as in your example code.
Or, since you are doing this setup manually as part of didFinishLaunchingWithOptions, you can also set window.rootViewController directly, though again that's not really recommended. XCode allows you to specify the app's default/root view controller and will automatically set it up for you when the app launches.
Actually you have just added the view alone. So the view alone will be retained. The viewcontroller will be released. But the viewcontroller needs to be the datasource and delegate for the tableview. Since it has been deallocated, that datasource will not have any valid reference and so it crashes.

I can make UINavigationController load only at 2nd level, not at Root View Controller

I tried looking for a similar problem but I could not find a similar question.
I am loading a UINavigationController in a UIView which is not (as in most examples) the MainWindow.
I created one new .xib called DocumentsViewController which is subclass of UIView (it has the related .m and .h files). And I created a DocumentsRootViewController.xib, which is a subclass of UITableViewController, which is supposed to be the UINavigationController's RootViewController.
I moved to DocumentsViewController and added a UINavigationController object in Interface Builder. Then I went to code, and added it as in IBOutlet, and connected it to the object.
In the ViewDidLoad, I execute the following lines:
DocumentsRootViewController *rootViewController = [[[DocumentsRootViewController alloc] init] autorelease];
rootViewController.title = #"Documents";
[navigationControllerDocuments initWithRootViewController:rootViewController];
[self.view addSubview:navigationControllerDocuments.view];
It shows the table as intended, but it shows a "Back" button to the "Root View Controller" (as in picture below).
Why? Shouldn't it already know that the rootviewcontroller has been set?
Thank you in advance to the ones that clarify this doubt
Giovanni
When you add the UINavigationController via the Nib it actually creates an instance of a UINavigationController inside the nib file with a default RootViewController set (of type UIViewController) and with a default title of RootViewController.
When you load the nib, this object is being created as part of loading the nib (i.e when you initialise DocumentsViewController) - so the navigationControllerDocuments outlet is already initialised as a UINavigationController with the default ViewController already set on it.
What I think is happening is when you call 'initWithRootViewController' - you are calling this on an already initialised object - so it is running the initialisation code again - pushing the second view controller (the DocumentRootViewController) onto the stack, but the default one that was created in the nib is already there.
What you should probably do is forget about creating one in the nib and initialise the whole thing programatically.
i.e. where you do:
[navigationControllerDocuments initWithRootViewController:rootViewController];
I suggest that you do an alloc and init instead:
[[navigationControllerDocuments alloc] initWithRootViewController:rootViewController];
Since you are doing this you really don't need to have the navigation controller added to the nib so if this works you should remove it from the nib since you are replacing it with this one in code.

iPhone How To Save View States

I have been developing iphone applications for around 3months now and theres a few things that stump me and i don't really have an idea how to work round them.
I have a navigation controller controlling the views in my application however every screen that is loaded, used then pushed back loses all the information as it seems to be reinstantiated... I believe this is a possible memory management issue?
But how to i create an app that navigates and retains all information in its views until the application is closed.
Thanks :)
Possible you didn't keep a reference to the view controller, the issue is for UIVIewController not to be released.
Make the view controller an ivar you will instanciate only one time when you push it on stack.
// in .h
MyViewController *mVC;
// in .m
// maybe when the user selects a row in a tableview
if(mVC == nil) {
// first time use, alloc/init
mVC = [[MyViewController ....];
}
// then push on the stack
[self.navigationController ....];
Of course don't forget to release it later.
In this part:
MyViewController *myViewController=[MyViewController alloc] initWithNibName:#"myView" bundle:nil];
[[self navigationController] pushViewController:myViewController animated:YES];
[myViewController release];
You will probably have something like this... Instead, make your myViewController a class's property so you have a reference to it. And drop the [myViewController release]; statement.
Possibly your app is receiving a didReceiveMemoryWarning.
In such cases, when the super class is called, the framework does memory cleaning by unloading all the views that are not currently displayed. This could explain the behavior you are seeing.
To check it further, override didReceiveMemoryWarning in one of your view controllers or applicationDidReceiveMemoryWarning in your app delegate, and put a breakpoint in it. Don't forget to call [super...] appropriately, otherwise pretty soon your app will be killed. What you should see in this way is that the views do not disappear before hitting the breakpoint, and do disappear after that.
If the hypothesis is correct, you should find a way to save the state of your view in viewDidUnload and restore it in viewDidLoad. Look also at didReceiveMemoryWarning reference.
Try to save data in NSUserDefaults it its small or use plist or it its too small like 5-10 objects save in in some variable in appDelegate, and if its too large use sqlite and for saving something like images of files like xml use Document directory
The UINavigationController works like a stack: you push and pop UIViewControllers on it. That means when a UIViewController get popped, it will have its retain count decremented by 1, and if no other object holds a reference to it, it will be deallocated. You can avoid the UIViewControllers getting dealloced by keeping a reference to them yourself by calling -retain on the objects, for instance in your appDelegate.
You can use NSUserDefaults to save the states of the UIControls in the view.
So whenever u r loading a view, set the values to the controls so that it looks like it resume from the place where we left.

UITableViewController loading inside a UIViewController inside a UIViewController issue

I don't really know if what I'm doing is the right way to do it. Right now it seems to be working until it hits a certain point with a EXC_BAD_ACCESS message.
I'll describe what I'm doing as best and with the most relevant details I can tell:
I have a CalendarViewController that inherits UIViewController which is loading from a .xib file (CalendarViewController.xib). The class contains a UIView called contentView which I created and which I initialize with another nib file based on a class which is also inherited from UIViewController:
- (void)viewDidLoad {
[super viewDidLoad];
calendarView = [[CalendarView alloc] initWithNibName:#"CalendarView" bundle:nil];
[contentView addSubview:calendarView.view];
}
(calendarView is the class inheriting UIViewController and viewDidLoad is from CalendarViewController.
CalendarView.xib has a UITableViewController with it's respective UITableView. This Table View Controller is linked to a CalendarTableController to which I also generated a .xib file for it.
Everything is being created just right (apparently) but it is crashing somewhere very unexpected. CalendarTableController also implements a DateLoaderDelegate which loads information from an xml on an external url.
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// When the data has all finished loading, we set a copy of the
// loaded data for us to access. This will allow us to not worry about
// whether a load is already in progress when accessing the data.
self.lastLoadedMatchXMLData = [self.matchXMLData copy];
// Make sure the _delegate object actually has the xmlDidFinishLoading
// method, and if it does, call it to notify the delegate that the
// data has finished loading.
if ([_delegate respondsToSelector:#selector(xmlDidFinishLoading)])
{
[_delegate xmlDidFinishLoading];
}
}
The application is getting to this point without any problem. _delegate is containing the correct object (a CalendarTableController which implements the DateLoaderDelegate). But when it arrives to the line:
if ([_delegate respondsToSelector:#selector(xmlDidFinishLoading)])
it crashes with the EXC_BAD_ACCESS, I don't really know the reason, if I look at the debugger, the crash is not occurring in any of my classes as any of them are appearing in the execution stack. URLConnectionClient seems to be generating it, but I don't really know why. The loading of the xml had worked earlier before I rearranged the ViewControllers to work as I have described now.
Any ideas?
It's weird. I fixed the problem but I had to dedicate the whole UIViewController to contain the UITableView. What I did was this:
Create an IBOutlet with the custom UITableViewController (CalendarTableViewController) in the custom UIViewController.
In the loaded .xib file I linked the IBOutlet to a created UITableViewController declared as a CalendarTableViewController.
This way I solved the problem of the UITableViewController being deallocated without reason. But now the image views I had placed in the intermediate UIViewController wouldn't appear. I had to set that UIViewController to contain solely the CalendarTableView and place the image views in the initial UIViewController. Weird, isn't it? I don't like much the hierarchy I created... but for now that will do =S
Check that you have defined properties for all of your subviews and that you are retaining everything that you need to be. Bad Access May mean that you're attempting to call respondsToSelector on an object that has been released.
Have you tried calling loadView before adding the nested controller's view to the parent's view?
Maybe viewDidLoad is not executing before you add the view and some variables were never initialized.

UIView subviews don't responde to delegates

I have following code in viewDidLoad
myViewController = [[UIViewController alloc] initWithNibName:#"myView" bundle:nil] ;
self.myView = myViewController.view;
[self.view addSubview:myView];
This code loads view from myView.nib (I have corresponding view controller m and h files of course). myView view has UITextField and other controls. So far so good - I can see all my controls on the screen.
The problem however is that even though I set a delegate for UITextField to be File's Owner (which is myView) and I implement UITextFieldDelegate in myView.m, delegate methods are never fired!
This does NOT happen if I add UITextField to the original view (created by the XCode as default template). Why is this happening?
The reason I need to useSubview because in actual code will layer view to the UIScrollView so I can pan and zoom.
THanks!
My first question to your question is, "is there a reason to use UIViewController to load your NIB file?".
It appears that you're "throwing away" the UIViewController and merely using it for its ability to load a NIB file. I'd stop that first, as that may help you debug this issue. Use:
self.myView = (UIView*)[NSBundle loadNibNamed:#"myView"];
The second part I'd question is that you say "File's Owner" -- because you're using a separate UIViewController, you may have it set to call back to your UIViewController, not the code that you mean to callback to. Maybe you could tell us a little about the setup of the XIB file?