NSobject's release query? - iphone

hi i am a newbie developer, building my first app, i have a impportant question -
lets say we are using TableviewController and have used few NSMutableArray objects and have a ManagedObjectContext object to fetch the data to display. now if i move to another view and release all the object i have instantiated using [[nsObject alloc] init] in the present view, it all works fine in we are in the next view but as soon as we click back button we dont have the NSObjects thatwe used to create the previous view so the app Crashes. what i did was left the objects without releasing. is it good or bad?

You usually shouldn't be releasing just for pushing another view controller on the stack. You should release when you don't need the objects anymore. In this case, you need the objects still because you are coming back to it. I would release your objects in your dealloc method, called whenever this view controller is done with them and is getting released itself.
If you are determined to release them as you push the app, you will need to re-fetch them when you come back before trying to do anything, this is much more complicated when compared to just retaining them.

Another Idea is to save the data in pList but it depends what you are saving. when you change the view, save it and when you come back again to the same view, retrive it from the plist

Related

How do I keep an object created within a method alive in objective-c?

I want to place multiple pie charts in my application that I create using core plot. I made a wrapper class (lets call it PieChartViewController) that is a view controller and sets up the graph and some buttons and actions to make the graph interactive. To deploy it, I usually just create a property on another view controller that holds the PieChartViewController and when I am initializing this view controller I simply alloc/init thePieChartViewController and add its view to the main view. This usually works fine.
The problem is that on another view, I want to add a variable amount of graphs to the view and this number is decided when the view controller is initialized. I have a method that initializes each PieChartViewController and adds it to an NSMutableDictionary on the parent so that I could keep a reference to them. However, this doesn't seem to keep them alive because I always get BAD_ACCESS 2 crashes and when running instruments I realized that they get deallocated.
So when the PieChartViewControllers are stored on a property it's all good, but when I put them in a dictionary they seem to not be kept alive long enough. I am still not very familiar with memory management in objective-c and I'm not really sure how to go about this, would appreciate any help.
I simply alloc/init the PieChartViewController and add its view to the main view. This usually works fine
It may work fine, but don't do it. This is a misuse of UIViewController. See my answer here: https://stackoverflow.com/a/15962125/341994

How to release a view when it's not visible in a tabbar controller?

I have a simple app with a tabbar navigation interface.
It has three view (A, B and C) and a modal view. Each view has its own view controller and nib . They are all designed and connected in the interface builder.
I'd like to release views which are not visible.
Tried release and nil them when another view appears such as
[[[self.navigationController.viewControllers objectAtIndex:0] view] release];
[[self.navigationController.viewControllers objectAtIndex:0] view] = nil;
etc.
It doesn't cause any issues but when I run instruments it does not make any difference. I don't see any drop in memory usage
I would appreciate your help
as #Daryl Teo wrote you should release and recreate in viewWillDis/Appear and (thats why I write this answer) you have a method called didReceiveMemoryWarning, use it!
You can simply log out whenever it gets called and test it with the Simulator included memory warning test function.
Simply open a tab, open another tab and call that test function. Your debug console should print out the log. If not you should double check if you have released all objects maybe someone is over-retained (which again should be released in viewWillDisappear).
The drop in memory usage might not be significant, depending on what the released viewController holds on to. I sugest you out a NSLog into the 'dealloc' of the viewController to see if it really gets dealloced or if there is some other object still holding on to it. Remember that release won't free the memory, it will only do so (by calling dealloc) if the objects retain count reached 0.
You don't want to do this. Let the TabBarController handle your view controllers for you. (It will already retain your viewController internally so whatever you do will only make retain count go out of sync)
You may be able to make it more memory efficient if you release objects in viewWillDisappear. Then rebuild the data again in viewWillAppear.

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.

Deallocation when iPhone is turned back on from sleep and app is still open

There are a few instances where my app crashes when turned back on from sleep and the app is still open. It happens if a UITableViews is open when the iPhone is put into sleep; the table is being filled from an XML being parsed. I understand why it is crashing; in my viewDidUnload method I am releasing the array that is filling the table. How to handle this I am not sure; yes I could simply not release it in viewDidUnload, but then it would never leave memory if you returned to the main menu.
Any help would be appreciated!
The method viewDidUnload is not the right place to release your data if at all. I quote Apple's documentation, which desribes it better than I could:
This method is called as a counterpart
to the viewDidLoad method. It is
called during low-memory conditions
when the view controller needs to
release its view and any objects
associated with that view to free up
memory. Because view controllers often
store references to views and other
view-related objects, you should use
this method to relinquish ownership in
those objects so that the memory for
them can be reclaimed. You should do
this only for objects that you can
easily recreate later, either in your
viewDidLoad method or from other parts
of your application. You should not
use this method to release user data
or any other information that cannot
be easily recreated.
ViewDidUnload is used only to release view related objects. A view controller can release its view because its not shown, still your instance of that controller exists and so does your model.

Where to put cleanup code in UIViewController?

I have a UIViewController subclass that loads a bunch of images for each cell in a tableview asynchronously which is handled by a separate download class. I keep a list of all of these download requests in a dictionary which is keyed to the index of the cell that is requesting the image.
My question is i where should i put the code that cancels the image download if the viewcontroller is popped off the navcontroller? I need to do this because if the user hits back while there are still images being downloaded (which could take a while) then when they are finished downloading the viewcontroller has already been released.
I cant put it in the viewWillDisappear method because i do not want to stop the download if the user clicks on a separate tab and only when the hit the back button. For now i put this code in the viewcontrollers dealloc method which works fine although it doesnt seem right for some reason. I thought of using the viewDidUnload method but it seems this is only called when there is a low memory warning?
Any ideas?
dealloc is the perfect place for this as the view controller gets deallocated and you are responsible to clean your stuff up.
You may want to consider putting the code in viewWillDisappear: anyway, after all if the screen you are navigating to needs anything loaded it will be slowed by the background image load...