I am having a uiviewcontroller instance and when I am releasing it the dealloc method of it is called.
I have released some objects in dealloc method of that uiviewcontroller.
If I comment [super dealloc] the app is working fine but if don't it is crashing.
I think there is no problem with the releases that I am doing in that method, but if I do [super dealloc] it is crashing.
Can any one help me out with this?
Hard to tell from your post without more information, but does your dealloc method look like this?
- (void)dealloc {
[super dealloc];
self.someProperty = nil;
}
Because if it does, you're calling a setter method on a deallocated instance. You should always call [super dealloc] last:
- (void)dealloc {
self.someProperty = nil;
[super dealloc];
}
Not sure if that helps. Try posting what your dealloc method looks like if not. Hard to troubleshoot in the dark.
It's not possible to help you without more information. The code you described is perfectly fine. The problem is in some other part of your app.
You probably access the view controller after releasing it, so the problem is not the [super dealloc] but any other place in you application that accesses the view controller.
Maybe you are releasing the controller in the wrong place. That could be why your [super dealloc] in your ViewController.m is crashing
You shouldn't called [viewController release] until you want that controller to die. For example, if you have an application with just a viewcontroller you must not release it until the application ends. This is because that controller needs to stay alive all the time to control the view. If you have in your ApplicationDelegate something like this, it will crash:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
UIViewController *controller = [[UIViewController alloc] init];
[window addSubview:controller.view];
[controller release]; //this will crash
}
Instead of that you should place your viewcontroller in the header file (.h) and release it in the dealloc method:
- (void)dealloc {
[controller release];
[window release];
[super dealloc];
}
I hope this helps.
Related
I am trying to make a simple iphone app and I have been playing around with features and recently, delegates. I am just confused with regards to memory management because apparently "good code" makes my app crash with exc_bad_access.
I have an object with two data members and implementation empty for now.
#implementation semester: NSObject{
NSInteger ID;
NSString *name;
}
then my delegate method:
- (void) receiveSemester:(semester *)newSemester {
[test setText:newSemester.name];
}
and a view that is used as a form which has:
#interface addSemesterController : UIViewController {
id<ModalViewDelegate> delegate;
UITextField *txtName;
UILabel *prompt;
UIButton *ok;
UIButton *cancel;
}
all objects are made properties and synthesized in the application file. Here is the method that used the delegate:
- (IBAction) okClick:(id)sender{
// create semester object and return it
semester *created = [[semester alloc] init];
created.name = txtName.text;
[delegate receiveSemester:created];
[self dismissModalViewControllerAnimated:YES];
}
And my dealloc method looks like this:
- (void)dealloc {
/*
[txtName dealloc];
[prompt dealloc];
[ok dealloc];
[cancel dealloc];
*/
[super dealloc];
}
With the deallocs of the objects contained in the form commented out, my app runs ok. However, when I uncomment them, I receive the exc_bad_access error in my delegate protocol:
// in main view controller
- (void) receiveSemester:(semester *)newSemester {
[test setText:newSemester.name];
// test is a UILabel
}
I tried the zombie method and it says that the label calls a released object. I am not releasing my semester object in the "form" controller, and even if I was the delegate function is called before deallocating the view.
Clearly I should not be releasing the objects in the dealloc method, I am just unclear in the why I shouldn't.
Again, thanks in advance for the help.
Use release to release the variables instead of calling dealloc on variables, due to this you are having issue -
- (void)dealloc {
[txtName release];
[prompt release];
[ok release];
[cancel release];
[super dealloc];
}
try writing
[txtName release];
[prompt release];
[ok release];
[cancel release];
instead of dealloc and these objects will be deallocated properly
Using the PhotoScroller example from Apple, to reuse the memory allocated for views, I cannot get the memory released once the retain count hits 0. Here my code for a better understanding:
This piece is an extract from PhotoScroller
PhotoViewController.m
- (void)configurePage:(ImageScrollView *)page forIndex:(NSUInteger)index
{
page.index = index;
page.frame = [self frameForPageAtIndex:index];
[page displayPage:index];
}
ImageScrollView.h
#interface ImageScrollView : UIView
{
UIViewController *vc;
NSUInteger index;
}
#property (assign) NSUInteger index;
- (void)displayPage:(int)indice;
#end
ImageScrollView.m
- (void)dealloc
{
[vc release];
[super dealloc];
}
- (void)displayPage:(int)indice
{
//remove previous view
[vc.view removeFromSuperview];
[vc release];
vc = nil;
//NSLog(#"vc retain %i", [vc retainCount]);
// make a new viewController for the new page
Class clss = NSClassFromString([NSString stringWithFormat:#"page_0%i", indice + 1]);
vc = [[clss alloc] initWithNibName:[NSString stringWithFormat:#"page_0%i", indice + 1] bundle:nil];
[self addSubview:vc.view];
}
The classes "page_0x" are UIViewControllers. So far have nothing but a UIImageView on the XIB.
An example of page_01:
#implementation page_01
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Overriden to allow any orientation.
return YES;
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
}
#end
Memory peaks to 148 MB on device. Gives me a memory warning Level 1, then releases some memory. Goes down to 95 MB. Keeps going up and down.
Perhaps your page_0x view controllers are getting freed, but something they've created isn't. Some things to check:
Set a breakpoint in the dealloc method of your page_0x view controllers. Is it getting called?
Check all the IBOutlets and other instance variables of your page_0x view controllers. Are they all being released properly in their class's dealloc method?
Run Build & Analyze. Does it turn up anything?
Try running the Leaks Instrument. It can tell you what kind of objects are actually leaking.
(EDIT) Grasping at straws now. You don't have NSZombieEnabled turned on, do you?
(EDIT 2) You say you're throwing a .png on it. What happens if you remove that .png?
If you're running in the simulator, try it on the device. (See this question.)
If I have a viewController setup as below:
#interface MapViewController : UIViewController <MKMapViewDelegate, CLLocationManagerDelegate> {
CLLocationManager *locationManager;
}
-(void)viewDidLoad {
[super viewDidLoad];
locationManager = [[CLLocationManager alloc] init];
}
when it comes to memory management should I be adding release to both viewDidUnload & dealloc?
-(void)viewDidUnload {
[locationManager release];
locationManager = nil;
[super viewDidUnload];
}
-(void)dealloc {
[locationManager release];
[super dealloc];
}
cheers Gary
EDIT:
[super dealloc] moved to bottom as per Deans kind comment.
Short answer :
Unless you are creating/retaining it in viewDidLoad (or a xib), don't release it in viewDidUnload.
Long answer :
viewDidUnload is used to release anything that you might have made when the view is created - this included things in viewDidLoad but also includes and IBOutlet properties that are created from inside a xib file. these should all be released and set to nil in viewDidUnload.
Anything else should just be released in dealloc.
The idea is that if viewDidUnload is called to free some memory, the view can be recreated again completely from your viewDidLoad method.
In viewDidUnload you should be setting your IBOutlet properties to nil and anything that is initialized in viewDidLoad.
Remember that if the phone is low on memory, your view will be unloaded if it isn't on-screen. Next time your view is loaded again, new views will be connected to the IBOutlets and viewDidLoad will be called again. So you should set the outlet properties to nil in viewDidUnload to reduce the memory footprint.
The guy is doing a [object release] before doing the self.object = nil;
Is the first release for nothing ? In the Apple documentation, they simply affect nil to the variable... what is right?
I would like to know if there is any difference between calling [super viewDidUnload] before realeasing properties or after it.
Thank you!
self.webView = nil;
self.fullText = nil;
[super viewDidUnload];
or
[super viewDidUnload];
self.webView = nil;
self.fullText = nil;
This depends on what the superclass does in viewDidUnload. If it's just a standard UIViewController, either will do because -[UIViewController viewDidUnload] does nothing.
I never thought it mattered, but we just found a bug where the app crashed calling it first. The trend at my office has been to call it last, but the Apple template puts it first.
You can do what you want, but I will always call it last from now on.
This question is not fully answered. (And it's first hit when I google on this topic, so a complete answer would be useful to me and others.)
If the superclass DOES something in viewDidUnload, then what is the correct order for calling it in your class's viewDidUnload: before or after releasing properties?
For the record, it seems the consensus is to call the super method LAST:
-(void)viewDidUnload {
self.some_property = nil;
[super viewDidUnload];
}
This only matters if the superclass of your view actually does something in viewDidLoad. The default UIViewController doesn't do anything in viewDidLoad so if your view is a standard UIViewController then you can put [super viewDidLoad] anywhere in the viewDidLoad method. However, if super does something in viewDidLoad, then it does matter where you put [super viewDidLoad].
This is just like the dealloc method.
- (void)dealloc
{
[array release];
[super dealloc];
}
So I think we should call [super viewDidUnload] last.
I'm dealing with viewDidUnload and dealloc methods and I've founded a problem when calling [super dealloc]; in parent view controller.
I have a lot of view controllers with custom code which I have putted outside on a parent view controller. So, when defining my view controllers I set a reference to the super class:
#interface LoginViewController : AbstractViewController
Then, at the dealloc method I call the AbstractViewController dealloc method:
//(Login View Controller code)
- (void)dealloc {
[user release];
[passwd release];
[super dealloc];
}
[super dealloc] execute the following code:
//(Abstract View Controller code)
- (void)dealloc {
[dbUtils release];
[loadingView release];
[super dealloc];
}
If I simulate a memory warning on iPhone Simulator, the following exception is thrown:
2010-03-03 11:27:45.805 MyApp[71563:40b] Received simulated memory warning.
2010-03-03 11:27:45.808 MyApp[71563:40b] *** -[LoginViewController isViewLoaded]: message sent to deallocated instance 0x13b51b0
kill
quit
However, if I comment the [super dealloc] line in AbstractViewController the exception is not thrown and my app still running.
Thank you for your help once again!
It looks like you're freeing your view controller but then trying to use it again. When you free your view controller because of the memory warning, remember to set the pointer to nil so you don't accidentally use it again. i.e. something like
[myLoginViewController release]; //!< Triggers the dealloc call
myLoginController = nil; //!< Makes sure we never use it again
or, if myLoginViewController is a property you can do this in a neater way :
self.myLoginViewController = nil;
Hope that helps,
Sam
Notice -didReceiveMemoryWarning does not trigger -dealloc, it triggers -viewDidUnload. So I guess it is your implementation of -viewDidUnload that does something wrong that causes the controller's final retention to be released so -dealloc is called. I've just encountered this problem in my code which is caused by a retain recycle that is released in -viewDidUnload.
This happened to me and took a while to figure out. One of the delegates was trying to send a message because the delegate was self and it was a strong reference. when I made it weak it seems to have fixed it.