iPhone How To Save View States - iphone

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.

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.

View transition without using navigation controller?

I want to implement view transition without using navigation controller like pushviewController mechanism. So, I created the view hierarchy like below.
window is superview and contains three subviews.
[window] - aViewController - bViewController - cViewController
If I want to go back to the aVewiController from cViewController, I simply allocate aViewController again like this: [[aViewController alloc] init].
Then, after 4 circulations, I got didReceiveMemoryWarning and "Program exited with status value:0" messages. Its obviously memory issue but no memory leak. Allocating viewcontroller over and over is a problem. I have no idea how to transit view in this case.
If you want your hierarchy of UIViewControllers to behave as they do in UINavigationController case you should
A) show your new ViewController with this call
//This code should be implemented in viewControllerA
[self presentModalViewController:viewControllerB animated:YES]
B) go back one step by calling
//This code should be implemented in viewControllerA
[self dismissModalViewControllerAnimated:YES]
Notes: The way you would tell viewControllerA that you want to close viewControllerB is by sending a NSNotification. The good thing about this is that if you want to go from viewControllerC to viewControllerA you simply send a notification to viewControlerA to dissmisModalViewController and it will recursively dismiss viewControllerC and viewControllerB for you.
Hope this helps
You should allocate them only once and transition between the views itself by hiding/unhiding them:
viewController.view.hidden = YES/NO;
You will need to make sure you are releasing your object after you add them to their superview. and Make sure that you are removing them from their superview when they are sent off screen....
If you want to reuse the object then you can keep them in a list and try to dequeue them like the table view does. This way you wont have to remake them each time.
If you add them to the subview and never remove them. then you will have multiple views that are no longer used that are still being referenced by their super view. therefore they will still be in memory.

how to know whether dealloc is getting called or not in iphone sdk?

i am using UIviewcontroller subclasses. In my main view i have 3 buttons, each button will load a different nib. and each new nib is having one back button to come back to main view.
when i click one the back button of any view to move to the main view the dealloc of that view is not getting called? i didnt understood this.
can anyone explain when those views dealloc will be called?
if the dealloc method hasn't been called, it means that your retained your viewController object by hands. for example, in this case dealloc will not be called after clicking back button to return
MyViewController *controller = [[MyViewController alloc] init];
[self.navigationController pushViewController:controller animated:YES];
You should add
[controller release];
to this code to be sure that your instance of viewController will be deallocated. If you are absolutely sure, that you had sent equal number of alloc(or any message that increases object's retainCount) and release messages for your object and dealloc method doesn't be called anyway, it will be more complex. I hope that this answer will help. If you will find that your situation is "more complex", post a comment, then I'll try to explain with more details.
I too would like to dive deeper into understanding memory management details (below surface level) where it comes to controllers being pushed on and off of the stack. I built my framework from the text, "Beginning iPhone 3 Development" by Mark and LaMarche, but that text effectively re-uses sub-controllers and their dealloc methods never get called.
I have noticed that repeated use of a sub-controller with a NIB containing a UIWebView that calls Google's web directions url ... eventually results in a memory warning and my data is lost. This involves repeated "reuse" of the sub-controller.
If you can point me as well to in depth text that goes into nav controller and sub view memory management, that would be excellent.

How to avoid data lose when UIImagePickerController unloads my controller?

I am using UIImagePickerController to take a photo from the camera. However, the I find that randomly my calling controller (the one that is shown before the UIImagePickercontroller is shown) gets unloaded. I logged the viewDidUnload, and indeed it does get called. When the camera is done and dismissed, my controller's viewDidLoad will be called, unfortunately all the state is now gone. Things like text entered or things selected will be gone.
Obviously this is something to do with running out of memory. But is this behavior normal? Should I be handling it? This is NOT typically how modalViewController works. Usually you show it and dismiss it, everything should be intact.
What is a good way to avoid data lost in this case? Should I have to write a bunch of code to save the full state?
what's happening is that your view controller's didReceiveMemoryWarning is being called, and then since your view isn't visible, it's being unloaded.
the solution is that any data that wants to be persistent should be stored in your view controller rather than in your view.
you can prevent this from happening by providing an implementation of didReceiveMemoryWarning in your UIViewController class that doesn't call [super didReceiveMemoryWarning] which is where the unloading of the view happens, but it's still a good thing to try to understand what's going on.
It's really not advisable to override -didReceiveMemoryWarning so that UIViewController can't deallocate the view because then you may run into a "real" problem of low memory and your app will be forced to quit by the system.
What you really should do is store the text and other bits of entered data from the view in your -didReceiveMemoryWarning method (making sure to call super). Then in -viewDidLoad you can put the text and other bits back into the UI.
This will lighten the memory usage and reduce the likelihood of your app being forced to quit because there's no more memory left. All the while, the user won't know it ever disappeared!
My solution to the same issue described above was to declare an instance variable in my view controller which stores the contents of the UITextView should the view get unloaded. Thus in my viewWillDissapear method I save the contents of UITextView.text into my instance variable and in my viewWillAppear method I restore the contents.
- (void)viewWillAppear:(BOOL)animated
{
if (messageTextString != nil)
{
textEdit.text = messageTextString;
}
[super viewWillAppear:animated];
}
(void)viewWillDisappear:(BOOL)animated
{
self.messageTextString = textEdit.text;
[super viewWillDisappear:animated];
}

iPhone: Reusing UIViewControllers in order to save memory

what are best pratices to reuse UIViewControllers? In many apps (including Apple's own examples: e.g. SQLiteBooks), UIViewControllers are allocated and initialized everytime, a UIViewController is pushed to the stack. This increases the use of memory with every new controller, because the objects stay in memory and aren't used again.
How to make it better?
This increases the use of memory with
every new controller, because the
objects stays in the memory and aren't
used again.
It should be released when the stack is popped though, as long as you have not got something else holding on to it. Check your dealloc methods are getting called.
Also if it is pushed to the stack, then you need to keep it around at least until it is popped (which automatically happens if you follow the standard patterns). So it is used again.
So following the standard pattern should already keep your memory usage as small as you can get away with.
This is what I do when creating a new viewcontroller and the memory is released when the view is removed from the window
MyViewController *mvc = [[[MyViewController alloc] initWithNibName:#"MyView" bundle:nil] autorelease];
[[self navigationController] pushViewController:mvc animated:YES];
Do you actually have a memory issue that you are trying to address or is this a case of premature optimization? I would say that unless there is a specific resource issue then the best practice would be to follow the standard view controller patterns.
Put a breakpoint in your view controller's dealloc function, and make sure it is called when you remove the view controller from the window. The memory shouldn't keep building up. If you're properly creating and autoreleasing your controllers (as LostInTransit shows above), the memory for each controller should be released when it is removed.
If you see that dealloc is not getting called, it means that somewhere in the app a reference to the view controller still exists.
Don't forget that a View Controller is not your view.
Views held by a view controller can unload, so view controllers themselves are very lightweight. If you want to keep the footprint really light you could nullify any other data the controller has allocated in viewDidUnload (mostly called when there's a memory warning - it's a 3.0 only thing though).
As noted mostly view controllers will be deallocated when you leave them (hit back) so there aren't generally that any hanging around anyway. But sometimes I find it handy to leave a reference around if I want to re-open that view in the same state the user left it (does not work between app launches).