Objective C memory leak issue - iphone

The Leaks instrument tells me that I have a leak in this code fragment. Why is this so?
This code fragment is in viewDidLoad().
UINavigationItem *navItem=[self navigationItem];
UIBarButtonItem *addFeed = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(addFeed)];
[navItem setRightBarButtonItem:addFeed]; // leaks says that 128 bytes leaked
[addFeed release];
UIBarButtonItem *reload = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:#selector(reload)];
[navItem setLeftBarButtonItem:reload]; // leaks says that 128 bytes leaked here too !
[reload release];
[navItem release];

You should not be releasing navItem. You did not alloc/retain/new/create it, so you do not release it.
Other than that, your code looks fine. Is that everything in the method?

The leaks instrument only tells you where the leaked memory was allocated; it can't tell you where the memory should have been released but wasn't since there's no possible way for it to know that. Your leak is occurring elsewhere.
This code is mostly fine, except you should not be releasing navItem at the end. You are not an owner of it, since you didn't create it with a method named alloc, new, or copy in its name, so you should not release it.

if you're still getting the leak message and can't track down the bug, you can try using the static analyzer included in the latest and greatest Xcode (version 3.2)
Build > Build and Analyze
it'll use LLVM-Clang to statically analyze your code in a pretty way.
http://developer.apple.com/mac/library/featuredarticles/StaticAnalysis/index.html
UPDATE:
in your code snippet:
UINavigationItem *navItem=[self navigationItem];
UIBarButtonItem *addFeed = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(addFeed)];
[navItem setRightBarButtonItem:addFeed]; // leaks says that 128 bytes leaked
[addFeed release];
your leak is probably coming from setting the new rightBarButtonItem without releasing the old one.
this is what i think is happening:
1) get a handle to the navigationItem (has right bar button A)
2) create a new UIBarButton Item (making right bar button B)
3) setRightBarButtonItem to button B
now where's Button A? it should have been released by navItem when you set the new button. so you could have forgotten to release the button when you set it the first time, or you've got it retained somewhere else.

Do you have NSZombieEnabled? This causes objects not to be retained by the NSZombie instances and you'll see "leaks" when running the Leaks tool.

It seems that you're not releasing the view controller with custom viewDidLoad method.

[navItem setRightBarButtonItem:addFeed];
[navItem setLeftBarButtonItem:reload];
You are creating copies of the objects in these accessors. These accessors are incrementing the retainCount by 1. Your accessors should release each object and then immediately retain them.
Example:
- (void) setTitle: (NSString*) newTitle {
if (title != newTitle) {
[title release];
title = [newTitle retain]; // Or copy, depending on your needs.
}
Take a look at the techniques here:
Memory Management Programming
I believe that's what's up. So take a hard look at those two accessors.

Related

Strange behaviour of simulator & device when adding rightBarButtonItems to a UINavigationItem

In my application I am added two button at right of a UINavigationItem, its working fine on simulator, but when I testing it on device its gives me error of SIGABRT, along with unrecognized selector sent to NSArray. I tried to add one button at right side, it was added successfully, and works fine on device as well. Here my question is, whats the problem?
I am adding right buttons using following code,
NSArray *buttons=[[NSArray alloc] initWithObjects:btnOne,btnTwo,nil]];
myNavItem.rightBarButtonItems=buttons; //Error on device, but works fine on simulator.
Please, point me what is I doing wrong?
Thanks!
It appears that myNavItem is not an instance of UINavigationItem, but rather an instance of NSArray (which does not support setRightBarButtonItems). Could you show us more lines concerning myNavItem?
My suspicion is that myNavItem did not correctly retain the navigation item that it was originally pointing to. And that it points to an NSArray now by coincidence. This error might not occur in a debug setting if all objects are retained indefinitely for better logging.
If this code runs from an instance of a view controller try to use this line instead:
self.navigationItem.rightBarButtonItems = buttons;
On iOS prior to version 5: if you receive unrecognized selector sent to NSArray logs there is something wrong with your memory management. The log should read unrecognized selector sent to UINavigationItem on iOS prior to iOS 5.
Once the memory issue is fixed you should use a UIBarButtonItem with a custom view containing two UIButtons.
try adding these buttons to a UIBarButtonItem and add UIBarButtonItem to myNavItem like myNavItem.rightBarButtonItem = barButtonItem;
Your first line
NSArray *buttons=[[NSArray alloc] initWithObjects:btnOne,btnTwo,nil]];
has an extra right bracket at the end. Not sure if this would cause that error but it should cause some error.
You can use the UISegmentedControl. Check the UICatalog code sample to check its usage in the navigation bar.
UISegmentedControl *segmentedControl = [[UISegmentedControl alloc]initWithItems:[NSArray arrayWithObjects:btn1,btn2,nil]];
[segmentedControl addTarget:self action:#selector(segmentAction:) forControlEvents:UIControlEventValueChanged];
segmentedControl.frame = CGRectMake(0, 0, 90, 35);
segmentedControl.segmentedControlStyle=UISegmentedControlStyleBar;
segmentedControl.momentary = YES;
UIBarButtonItem *segmentBarItem = [[UIBarButtonItem alloc] initWithCustomView:segmentedControl];
[segmentedControl release];
self.navigationItem.rightBarButtonItem = segmentBarItem;
[segmentBarItem release];
}
This is the best way of adding as many number of buttons in your bar as you desire.Hope it gonna help u.
Thanks :)

memory leak in simulator

Instruments show me a leak in simulator in the following code,
UIBarButtonItem *connectButton = [[UIBarButtonItem alloc] initWithTitle:#"Connexion" style:UIBarButtonItemStyleBordered target:self action:#selector(pushViewController)];
[self.navigationItem setLeftBarButtonItem:connectButton animated:animated];
[connectButton release];
Do you see any leak ?? thanks
Leaks is showing you where the object was allocated, not where the object was leaked.
While the two might be the same, it is often much more likely that the leak of an object is caused by an extra retain or missing release somewhere else.
I don't see any leaks in the code you posted. That said, a couple questions:
How do you know that's where the leak is?
Any chance the getter for navigationItem is using copy? If so, there could be a leak there.
...and on device? You should check this on device. There are very, very few situations where you'd want to use the simulator for this kind of testing. It's not representative of how the device itself behaves. I'd recommend you test this on a device, and then if you're still seeing it come back here.

UIImageView got weird retain count and i need to release it twice to avoid leaks

I got a UIImageView that i set in the nib file. I download an image from internet and sets the image to the UIImageView. When i'm releasing it has retain count 2? If i'm using only 1 release it won't show any memory leak but i can see in "Instrument Allocations" that it never gets released. When i release the UIImageView twice like below then it works good. But i should never release it twice?!?!
in Header:
IBOutlet UIImageView *background;
in the .m loading the image:
/* Load Image code */
id path = [NSString stringWithFormat:#"http://www.image.com/aImage.jpg"];
NSURL *url = [NSURL URLWithString:path];
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSData* urlData = [[NSData alloc] initWithContentsOfURL:url];
[background setImage:[UIImage imageWithData:urlData]];
[urlData release];
[pool release];
in dealloc function:
- (void)dealloc {
NSLog(#"Backgroud count: %i",[background retainCount]); // Prints 2
[background release];
[background release]; // Does not "leak" if i have 2x release
[super dealloc];
}
This is the only code that is useing the UIImageView Background.
EDIT:
something i forgot to mention is that i run this code inside a for loop like this. but this for loop will only execute once! But it shouldn't matter?
for (id theKey in dictionary) {
/* Load Image code above is here */
}
I believe that I've figured out what the trouble is. Apple recommends that you retain the objects you connect to through IBOutlets (your image view, in this case). You said that you haven't done so, but you should be following Apple's recommendation. The reason that you should is outlined in a iphonedevsdk.com forum post about this problem, which links to a Big Nerd Ranch blog post that lays it all out.
On iOS, the nib loading mechanism uses the setter if your outlet has one, but it uses key-value coding if not; specifically, it uses setValue:forKey:, which retains the value (this is documented, but somewhat unexpected). Your image view, being the subview of your view controller's top view, is retained by that view. It's also retained by this key-value setting procedure. So, unbeknownst to you, your objects have two references to the image view. Apple makes the retaining property suggestion so that it becomes knownst to you that the view is being retained.
You still shouldn't be worrying about the retain count as such, but you should do one of two things: make this IBOutlet a retained property and release it in both viewDidUnload and dealloc (just once each, though!), or follow BNR's suggestion and make the property explicitly assigned:
#property (assign, nonatomic) IBOutlet UIImageView *background;
in which case you do not have to release it yourself. In both cases, make sure you #synthesize the property accessors.
Previously:
Don't look at retain count, and if there's no leak being detected, then don't worry about it. The UIKit framework is likely retaining the view for reasons that you aren't privy to.
Additionally, if background isn't a retained property:
#property (retain) IBOutlet UIImageView *background;
and you're creating it in the xib, you shouldn't be releasing it at all, because you don't own it. That is, you aren't responsible for its memory; the actions that give you that responsibility are: calling retain on the object, or creating it using a method whose name begins with alloc, copy, mutableCopy, or new.
I don't know much about nib file, i used to follow like below
background=[[UIImageView alloc] initWithFrame:CGRectMake(0,0,320,480)];
//Now the reatin count is 1
[background setImage:[UIImage imageWithData:urlData]];
[someView addSubview:background];
//Now the ratainCount will be 2 since we added the imageview to the superview
[background release];
//i will release immediately so the retain count drops to 1
. . .
//in dealloc or viewDidDisaaper i will remove the imageview from its superview
//then the retainCount will become 0 and the instance will be deallocated.
//it works for we without any memory leakage
[background removeFromSuperview];

UIWebView memory issues

I am playing youtube videos on a UIWebView which appears as a modalViewController subview (flip transition). Everything works fine, even though the UIWebView is released, I still receive memory warnings after a few repeated selection of this modalViewController.
I have added my UIWebView programmatically inside ViewDidLoad. Inside viewDidDisappear I check for [UIWebView retainCount] and if greater than 1, perform the following steps:
[[NSURLCache sharedURLCache] removeAllCachedResponses];
[self.webView removeFromSuperview];
self.webView.delegate = nil;
self.webView = nil;
NSLog(#"[self.webView retainCount] %d", [self.webView retainCount]);
I am running my code on xCode 3.2.5, iOS 4.2.
Appreciate all you help.
I think you are approaching the memory management problem in the wrong way. Checking the retainCount is a valid debugging technique if you know what you are doing. It is not, however, a memory management tool. In your particular case, if the UIWebView is being displayed it will always have retain count > 1. The superview will have a retain on it thus making the "if" useless.
If the webView property is well defined (i.e. noatomic, retain) the statement:
self.webView = nil;
should release the webView. A common mistake is to initialize the property with:
self.webView = [[UIWebView alloc] init];
This is likely to introduce a leak if the webView is defined as "retain". The correct way is
self.webView = [[[UIWebView alloc] init] autorelease];
If you can't display your controller several times without running out of memory you have a memory leak. Use Instruments (Leaks in particular) to find hte objects what are note being released properly. This is a good tutorial.
Be careful in keeping your retains and releases balanced and check for leaks.
Your problem will be related to this:
Is it possible to prevent an NSURLRequest from caching data or remove cached data following a request?
Scroll down to my answer for an extension of the accepted answer - i had this problem for days and it's now resolved!

uiimagepickerview controller creating memory leaks in iphone - why?

uiimagepickerview controller creating memory leaks in iphone - why?
Try to implement ui image picker view controller in your application & debug it.
You will find memory leaks in your application.
Why ui image picker view controller creates memory leaks.
-(void)addPhotos:(id)sender
{
if(imagePickerController==nil){
imagePickerController=[[UIImagePickerController alloc]init];
imagePickerController.delegate=self;
imagePickerController.sourceType=UIImagePickerControllerSourceTypeSavedPhotosAlbum;
imagePickerController.allowsImageEditing=YES;
imagePickerController.navigationBar.barStyle=UIBarStyleBlackOpaque;
}
[self.navigationController presentModalViewController:imagePickerController animated:YES];
}
dealloc of my view controller.
- (void)dealloc {
if(PhotoDateArray!=nil)[PhotoDateArray release];
if(imagePickerController!=nil) [imagePickerController release];
if(objDetail!=nil) [objDetail release];
if(Picimage!=nil) [Picimage release];
if(mySavePhotoController!=nil) [mySavePhotoController release];
if(LoadingAlert!=nil);
[super dealloc];
}
Video link explaining how I am getting the memory leak in it..
http://www.yourfilelink.com/get.php?fid=508534
Even though you have the nil check, it's still possible to leak memory. I think what is happening here is that you are calling alloc / init multiple times, but only releasing once. My guess it that addPhoto: is wired up to some button click, dealloc would only be called once when the delegate is trying to destroy. This creates a situation like this:
button click
alloc / init
button click
alloc / init (memory leak on first alloc'd picker)
close window
dealloc (free second alloc'd picker)
A better way might be the way Apple does it in the PhotoLocations and iPhoneCoreDataRecipes examples:
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.delegate = self;
[self presentModalViewController:imagePicker animated:YES];
[imagePicker release];
Then listen for the didFinishPickingImage and imagePickerControllerDidCancel messages to your delegate and a call to [self dismissModalViewControllerAnimated:YES]; in both places should suffice.
I dont know about the rest of the code, but do you ever have a release?
[imagePickerController release]
UIImagePickerController loads and initializes PhotoLibrary.framework the first time it is shown. This memory won't be reclaimed until your application is closed.
(the code you posted doesn't appear to have leaks as-is, but that doesn't mean it won't interact with the rest of your application in a way that causes them)
I can explain this because I was having the same problem.
Don't test memory on the simulator!
If you test the apple code on a device the memory problem disappears.
I was having a memory alloc leak which I found in Instruments. All I was doing was opening and closing the image picker (open/cancel) and using Apple code, my code and other people's code, just like yours above.
All were showing the allocation going up and up each time, as if the picker was not being released. If you tried to release it, it would crash (over released).
Then I found a really helpful web page which basically stated:
"This doesn't happen when testing on the device"
So I switched from the simulator and ran the tests on the device. Lo & behold there was no allocation increase and it behaved normally.
This however is totally evil and now we can place no trust in the simulator to do a reliable job.
I want to add this to save people, the time, pain and bewilderment of wondering wtf is going on!