0

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 */
}
Bohemian
  • 412,405
  • 93
  • 575
  • 722
David
  • 1,318
  • 1
  • 14
  • 28
  • Is it possible you have a @synthesize somewhere in your code for background ? – Jason Rogers May 13 '11 at 02:02
  • Nope, "background" is never mention anywhere else in the code but it was a good suggestion. Also forgot to mention the for loop. Read my updated my post for more info – David May 13 '11 at 02:10
  • You shouldn't be releasing it at all if you're allocating it in the xib and not retaining it in code. – jscs May 13 '11 at 02:29
  • From what i've been told you should always release your IBOutlets? Still dosn't explain why it has 2 retain count. When i release this ViewController background will still be allocated in the memory. – David May 13 '11 at 02:33
  • You only release if you're an owner. If what you said to Jason is accurate and you're not synthesizing a setter for this outlet, then releasing it is wrong. – jscs May 13 '11 at 02:35
  • Thanks for the advice about not release IBOutlets. Tho it's not the problem in this case. – David May 13 '11 at 03:19

2 Answers2

3

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.

Community
  • 1
  • 1
jscs
  • 63,694
  • 13
  • 151
  • 195
  • I know retain count is not accurate. The problem is that i crash my app by init this ViewController and release it about 20 times. Then the device is out of memory i will get memory warning and it will crash. When i'm using Instrument - Allocations i can clearly see that this image is never getting released unless i release it twice like i do in the code. So clearly using memory guideline wont help my app in this case. There has to be a bug or some other problems. – David May 13 '11 at 02:40
  • I'm sorry, I don't really understand what you're saying. If you know retainCount is useless, why are you using it? You're creating a view controller which owns a xib; the xib contains this `UIImageView` called background. The view controller does retain the image view or does not? Additionally, why do you have a loop that only runs once? – jscs May 13 '11 at 02:52
  • If i'm not releasing it twice my app will crash because of this low memory after createing and releasing this ViewController 20 times? Reason why i have a loop is because i'm fetching data from a servers database and will receive the data in a dictionary with dictionary's. First Dictionary contains rows from the database and the second level of dictionary's contains all the data in that row. I know i will only get one row in this case. – David May 13 '11 at 03:12
  • Are you verifying that assumption? Why are you creating an autorelease pool for a loop that you think only runs once? Why is the URL created outside that pool? Are you certain that the view controller is being freed? Is it the image _view_ or the _image_ that isn't getting freed? Please answer my earlier question about retaining the image view. – jscs May 13 '11 at 03:24
  • 1
    @David: I just did some research on your behalf and believe that I've found some useful information. Please see my updated answer. – jscs May 13 '11 at 04:20
  • That's an really good answer! Will test it in a few hours and come back to you. – David May 13 '11 at 11:04
  • I found the problem. The problem was that in the app delegate i created a viewController and added it's view to the [self.view addsubview:....]. Later i released the viewcontroller but forgot that the view had 2 retain count and the controller only had one. I followed apples documentation and it worked. Tho alot of other leaks occurred. http://developer.apple.com/library/ios/#documentation/iphone/conceptual/iPhone101/Articles/03_AddingViewController.html – David May 13 '11 at 14:58
0

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];
pradeepa
  • 4,104
  • 5
  • 31
  • 41