UIBarbutton item allocation leak - iphone - iphone

I am declaring a property for the rightbutton toolbar and allocating it like this
if(self.toolBar == nil)
self.toolBar = [[UIBarButtonItem alloc] initWithCustomView:tools];
self.navigationItem.rightBarButtonItem = self.toolBar;
- (void)viewDidUnload {
toolBar = nil;
}
- (void)dealloc {
[toolBar release];
[super dealloc];
}
When I come to this screen for the second time(2nd time viewDidLoad called), the UIBarbuttonItem is leaking according to Instruments. What could be wrong?
Thanks for all your help in advance.

You're niling the toolbar property prematurely - viewDidUnload will be called before dealloc, thus dealloc will have no chance to release the barbutton, because toolBar points to nil, not the object (which will remain owned (release count of at least 1) but without reference).
Plus, since you're not using the dot notation (self.toolBar) to nil out the property, the old objects release count would not be decreased! So its retain count is at least 2 at the time your controller will quit.
I'd release the object right after assigning it to your property, because the setter method has retained it anyway (if you choose to retain it in the declaration). Later in viewDidUnload all you need to do is self.toolBar = nil; to really get rid of it.

I guess your property is something like this?
#property (nonatomic, retain) IBOutlet UIBarButtonItem toolBar;
This will perform a retain automatically for you but you are giving your property an already retained toobar item.
Try this instead :
if(toolBar == nil)
toolBar = [[UIBarButtonItem alloc] initWithCustomView:tools];
self.navigationItem.rightBarButtonItem = self.toolBar;
If you don't use self. it won't use the property and therefor won't have that extra retain :)

Related

releasing a UILabel in dealloc crashes the app after it was retained, allocated & autoreleased

I have a UILabel in my class header file defined as :
`#property (nonatomic, retain) UILabel *label1;`
and it exists as instance variable like this:
`UILabel *label1;`
and synthesized in the .m file, however, in viewDidLoad method I do:
`label1 = [UILabel alloc] init] autorelease];`
then I do various things on the label like setting its frame, text color, etc ...
when the view controller is deallocated, the app crashes with this message in console
(Zombies enabled): `[CALayer release] message sent to deallocated instance` ...
The app will not crash when I :
1) remove the autorelease word .. or
2) if i do not release label1 in the dealloc method .. or
3) remove [super dealloc]; from the dealloc method of the view controller.
how can I properly release this UILabel without facing such crash !!
You are doing right.Autorelease and release in dealloc.
But it shouldn't be crash.Because I did the same thing to check.
Could you please check accciendlty may be u release the label some where else.
And releasing in dealloc again.
since you have declared the label as retain. The allocation can be
UILabel *myLabel = [[UILabel alloc] init];
// set all properties of label
self.label1 = myLabel;
[myLabel release];
myLabel = nil;
And in dealloc release your label1.
[label1 release];
this is the way I'm used to and this makes things smoother for me.
the label is released already before dealloc is called. that is because its an autorelease object. your dealloc is trying to release a UIlabel that already been released, an it crashes.. in your question. you can use 1 or 2. if you allocated the object once, then call a release just once. its not because you assign retain to your property in #property directive will add 1 retain count to your object , #property(retain) will not allocate anything, but will tell the compiler how you want your properties treated
strangely enough, when I used self.label1 = [[[UILabel alloc] init]autorelease]; instead of label1 = [[[UILabel alloc] init] autorelease]; solved the problem. the dealloc method remains as is without any change. really weird !!
Do this and u will not use autorelease for label1:
- (void)dealloc
{
if(label1)
{
label1 = nil;
[label1 release];
}
[super dealloc];
}

Another memory management query for ivars

There is undoubtedly a wealth of information re: memory management in iOS. Having read a huge amount about it, I am still unclear as to 'BEST' practice for certain situations. Please can I seek clarification on two examples below...
I have an NSMutableArray which is acting as a datasource for a tableView and a UIBarButtonItem called editButton both declared as follows:
#interface MyTableViewController : UITableViewController {
NSMutableArray *datasourceArray;
UIBarButtonItem *editButton;
}
#property (nonatomic, retain) NSMutableArray *datasourceArray;
#property (nonatomic, retain) UIBarButtonItem *editButton;
#end
I have then synthesized them and alloc'd/init'd them as follows:
#implementation
#syntesize datasourceArray, editButton;
-(void)viewDidLoad {
self.datasourceArray = [self retrieveDatasourceArray];
self.editButton = [[UIBarButtonItem alloc] initWithTitle:#"Edit" style:UIBarButtonItemStylePlain target:self action:#selector(editTable)];
[self.navigationItem setRightBarButtonItems:[NSArray arrayWithObjects:editButton, nil] animated:NO];
[editButton release];
}
-(void)retrieveDatasourceArray {
NSMutableArray *datasource = [[[NSMutableArray alloc] initWithObjects #"example1", #"example2", nil] autorelease];
return datasource;
}
-(void)dealloc {
[datasourceArray release];
[editButton release];
[super dealloc];
}
Question 1: The NSMutableArray
As you can see, I have separated the actual creation of the array into a different method as there is lots of code retrieving from core data and sorting going on (not needed for this question) which I wanted to separate out. I have therefore chosen to return an NSMutableArray which is autoreleased and set this to the self.datasourceArray which is defined in the header file. Is this a sensible and leak free way of implementing this?
Question 2: The Edit Button
As I need to change the title and style of the editButton later, I need to have access to it, hence declaring it. I then alloc/init it in the viewDidLoad method and added it to an array (with some other buttons not shown here) before using this array to add the buttons to the navigationBar. I have then released the editButton as I have alloc'd it and handed it to an array. Is this necessary or essential or even in the correct place given my dealloc method?
Many thanks in advance
EDIT: Further question 3:
When accessing either of these ivars elsewhere in my code (say when calling [datasourceArray count] or resetting the title of the 'Edit' button to 'Done', should I use self. notation or not?
EDIT: Further question 4:
Elsewhere I have used the following code to initialise a synthesised NSMutableArray. Given the below answers, is this more leaky...?
[self setDatasourceArray: [[NSMutableArray arrayWithArray: [self retrieveDatasourceArray]];
1st point for the Array
NSMutableArray *datasource = [[[NSMutableArray alloc] initWithObjects #"example1", #"example2", nil] autorelease];
return datasource;
here you are doing it correct..returning an autoreleased object..which will be retained by the variable because you defined it to be of type retain (when you did #property).
2nd point for the edit button
self.editButton = [[UIBarButtonItem alloc] initWithTitle:#"Edit" style:UIBarButtonItemStylePlain target:self action:#selector(editTable)];
[self.navigationItem setRightBarButtonItems:[NSArray arrayWithObjects:editButton, nil] animated:NO];
[editButton release];
Here you are apparently over releasing the object..
remember the variable retains the new variable you defined..so edit button retains the new bar button item..so releasing it . is necessary one time..which you do in dealloc..but releasing here also will lead to overrelease..to solve this just remove the release line and update your code to be like this
self.editButton = [[[UIBarButtonItem alloc] initWithTitle:#"Edit" style:UIBarButtonItemStylePlain target:self action:#selector(editTable)]autorelease];
[self.navigationItem setRightBarButtonItems:[NSArray arrayWithObjects:editButton, nil] animated:NO];
Here you see that the new instance which will be created will be auto released..and its value will be retained by your variable

Remove all subviews in dealloc?

My current understanding is that superviews have retains each of their subviews. For a subclass of a UIView, do I need to remove all of my subviews from their superview as part of dealloc? I'm currently just releasing my IBOutlets, removing observed notifications, and clearing up any pesky ivars.
Or is removing and releasing subviews part of a UIView's [super dealloc]?
As a part of the view's dealloc, the subviews are removed automatically. So you don't need to remove them. However, if your view has retained any of its subviews [aside from the automatic retain], you should release them during dealloc.
So for example suppose your view contained the following code:
[header file]
UILabel *myLabel;
#property (nonatomic, retain) UILabel *myLabel;
[implementation file]
someLabel = [[UILabel alloc]initWithFrame: someFrame];
[self addSubview: someLabel];
self.myLabel = someLabel;
[someLabel release]; // now retained twice, once by the property and once as a subview
someButton = [[UIButton alloc]initWithFrame: someOtherFrame];
[self addSubview: someButton];
[someButton release]; // retained once as it is a subview
then your dealloc method would look like this:
- (void) dealloc {
[myLabel release];
[super dealloc];
}
UIView retains its subviews, so it's responsible for releasing them. Your subclass doesn't own those views (unless you explicitly retain them), so you don't need to worry about releasing them.
So it sounds like you're doing the right thing.

How to remove segmentedcontroller from uinavigationcontroller after view pops?

I'm building a segmented control within my viewDidLoad method, like so:
NSArray *tabitems = [NSArray arrayWithObjects:#"ONE", #"TWO", nil];
UISegmentedControl *tabs = [[UISegmentedControl alloc] initWithItems:tabitems];
tabs.segmentedControlStyle = UISegmentedControlStyleBar;
tabs.frame = CGRectMake(185.0, 7.0, 130.0, 30.0);
tabs.selectedSegmentIndex = 0;
[self.navigationController.navigationBar addSubview:tabs];
[tabs release];
But when the user goes Back in the uinavigationcontroller hierarchy, the segmented controller stays on the navigation bar. How would I get rid of it? Or am I doing something fundamentally wrong?
EDIT
Following Alex's suggestions, I propertized tabs and tried:
NSArray *tabItems = [NSArray arrayWithObjects:#"FAQs", #"Terms", nil];
self.tabs = [[UISegmentedControl alloc] initWithItems:tabItems];
but I'm not sure it's a good idea to alloc a property;
And I'm using
[self.tabs removeFromSuperview];
in my viewWillDisappear. Is that enough?
Retain a reference to the segmented control in your view controller (i.e define tabs as a property in the view controller's header file).
Override the view controller's -viewWillDisappear: method, and remove the segmented control from the navigation bar there, using the control's -removeFromSuperview method.
EDIT
You would still alloc-init your segmented control tabs in -viewDidLoad. You just need to set up a retain property for tabs in your view controller's header, and move the control's release statement to the view controller's dealloc method.
Read the "Properties" section of this Objective-C tutorial for an introduction to properties and how to set them up.
The way to override a method is as follows:
- (ReturnClass) methodNameToOverride:args {
[super methodNameToOverride:args];
// your code goes here...
}
In the case of -viewWillDisappear:, this method gets called when your view controller is about to disappear, such as when it gets popped off the navigation stack. This is a great place to put code that manages clean-up of view-controller-specific items, like your segmented control:
- (void) viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[tabs removeFromSuperview];
}
EDIT 2
If your property is set as follows:
#property (nonatomic, retain) UISegmentedControl *tabs;
then you are going to retain anything you set self.tabs equal to.
Your code here:
self.tabs = [[UISegmentedControl alloc] initWithItems:...];
will create a memory leak, because you are retaining this object: [[UISegmentedControl alloc] init] — but you never release [[UISegmentedControl alloc] init] itself. This is bad.
Instead, use autorelease on the right side, i.e.:
self.tabs = [[[UISegmentedControl alloc] initWithItems:...] autorelease];
The tabs property retains its own reference to the initialized segmented control. That initialized segmented control is itself released properly at some later point. So no more memory leak.
Even better, set the UISegmentedControl's owning UIViewController's navigationItem.titleView to the UISegmentedControl.
-(void) viewDidLoad {
if(!mySegmentedControl) {
// initialize the UISegmentedControl
...
}
self.navigationItem.titleView = mySegmentedControl;
}
No manual removal of the UISegmentedControl or any other UIView for that matter required except, of course, releasing when owning UIViewController is dealloc'ed. Also, to be a "good memory citizen", you might set your property to nil in -viewDidUnload.
You can also customize the left and right barButtonItems of the UIViewController's navgiationItem.

iPhone - Memory Management problems

I am going over my code and trying to get a handle on proper memory management. This code:
imageView = [[[UIImageView alloc] initWithImage:myImage] autorelease];
Causes my application to crash. I am using multiple view controllers within a nav bar controller. The app works fine: I can select a person from the first view controller (tableview) and it puts me to a list of that persons photos, I can then select a photo from that view controller (tableview) and move to a final view with a scrollview for viewing the photo. Once I hit back on the navbar the previous view loads (list of photos in a tableview) however the app crashes right before the row is deselected using this code:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if(RowSelected != nil)
{
[MainTableView deselectRowAtIndexPath:RowSelected animated:YES];
}
}
The selected row is stored when a the user clicks a row.
If I leave the code as:
imageView = [[UIImageView alloc] initWithImage:myImage];
The app runs fine. Am I doing something wrong? Do I not need to autorelease this?
Make sure you create that view in your view controller's -loadView or -viewDidLoad, not in its initializer. When the controller's view goes offscreen it usually gets released, which in turn releases its subviews; thus, you should not expect your reference to imageView to remain valid. If you for some reason need the image view to stay in memory even when the view controller's offscreen, then it's okay not to call -autorelease when you create it; just make sure to call [imageView release]; in your controller's -dealloc.
When you mark imageView for autorelease, it will be released the next time thru the run loop. If you still are referencing or using imageView somewhere then you are using a pointer to heap space that has been released. The heap space will get overwritten (sooner or later) and you will be referencing garbage and crash.
I think the correct solution is that imageView should be a property that is retained, but I'm not sure what you are doing with imageView so I'm only guesstimating here. If you add imageView to your view Controllers view it will retain it in the subviews array. Bottom line, it has to be retained by whoever is using it.
You would make imageView a retained property in the .h file:
#property (nonatomic, retain) UIImageView* imageView;
Then use the setter, which will retain it:
UIImageView* tmpIV = [[UIImageView alloc] initWithImage:myImage];
self.imageView = tmpIV; // copy the pointer, setter will retain it
[tmpIV release]; // release the original alloc
Don't forget the #synthesize to create the setter/getter.
The ImageView is in my .h. I am using this line it in my -viewDidLoad, i do not need the view once it goes offscreen:
imageView = [[[UIImageView alloc] initWithImage:myImage] autorelease];
I think that what i am doing is assigning the allocated UIImageView to my imageView and if i auto release then the retaincount will be off because my -dealloc releases? (corret me if im wrong)
if i check my -dealloc:
- (void)dealloc {
NSLog(#"%i", [photo retainCount]);
[photo release];
NSLog(#"%i", [imageView retainCount]);
[imageView release];
[super dealloc];
}
The retaincount of the imageView is 1 in NSLog, im guessing that when it goes to do [super dealloc] that it tries to take 1 more retain count off of the imageView when it is 0 already because of the [imageView release] ?
if i have the line: imageView = [[UIImageView alloc] initWithImage:myImage];
then the retain count is 2 in NSLog, 1 going into the [supper dealloc]
if i use kk6yb's method, then the app works no problems, however i think i shouldn't have to do it this way because using his way if i check my retain count in dealloc it is also 2 in the NSLog...
I am confused, i read alot about memory management yesterday to get a better grip on things, since i am releasing the imageView in the -dealloc i believe i do not need to autorelease on that line?
Is there a way to check memory leaks in xCode?
Thanks!