I am newbie in iphone development and I could solve the problem from last couple of days. I would really appreciate if someone can help me solve the issue. Here is the problem
I am trying to pre fetch last and next image from internet and I have a class for asynchronous download. Following are the two properties I use to pass url and get Image.
Following lines are from its connectionDidFinishLoading method.
Code:
UIImage* downloadedImage = [[UIImage alloc] initWithData:m_ImageRequestData];
self.Image = downloadedImage;
// release the data object
[downloadedImage release];
FYI, m_ImageRequestData is has the data and it is successfully converted to UIImage.
Then I call delegate method in calling class to set requested images as current , previous or next.
There is a lot of UIImage allocation going on and actually these are memory leaks of UIImage I want to remove. if I remove these release and allocations the next and previous images are not set to imageview instead they raise exception. In debugger I have checked their values are not nil but still they raise error when assigning them to imageview. So I am releasing and re allocating these variables and now I m getting memory leaks. Any idea where I m missing things?
if(downloadedImage.Image != nil)
{
//[downloadedImage release];
if(downloadedImage.imgindx==curr_index) // current image is downloaded
{
[currentImg release]; // Generally speaking, there shouldn't be a reason to release a property like this. The old value will be released when a new value is passed in.
if(currentImg==nil)
currentImg=[[UIImage alloc] init]; // Never do alloc/init in the same line as assigning to a property. It's a leak. You don't need to create an object anyway, since you assign a new value in the next line.
currentImg=downloadedImage.Image;
imgView.image=currentImg;
}
You could probably make a small change to this and avoid that leak. I can't tell if 'currentImg' is a local or instance variable, so this assumes it is a property:
Code:
if(downloadedImage.Image != nil)
{
if(downloadedImage.imgindx==curr_index) // current image is downloaded
{
if([self currentImg]==nil)
[self setCurrentImg: [downloadedImage Image]];
imgView.image=currentImg;
}
Code:
else // if previous
if(downloadedImage.imgindx==curr_index-1)
{
// Same idea here...
[prevImg release];
if(prevImg==nil)
prevImg=[[UIImage alloc] init];
prevImg=downloadedImage.Image;
}
else //if next
if(downloadedImage.imgindx==curr_index+1)
{
// And here...
[nextImg release];
if(nextImg==nil)
nextImg=[[UIImage alloc] init];
nextImg=downloadedImage.Image;
}
The variable will only be nil before ever being assigned or if you manually set it to nil. Simply releasing the variable, even if it is deallocated, will not set the pointer back to nil. If you really want to do something only if the variable is deallocated you can check the retain count before releasing it (if you do it after you may get a message send error). But normally you should just release it and then reassign it because it not being deallocated assumes that some other piece of code is still using it (if you are retaining and releasing correctly).
Last edited by drewag; 08-11-2009 at 10:15 AM.
Reason: typos
Thanks for the reply.
That really make sense and I am already done with the code changes you suggest after revisiting some of memory management articles. Unfortunately I m still getting leaks of UIImage and InternetImage(class for asynchro download image). I really dont know where to release this object.
I alloc and init its(InternetImage) object every time user press next or previous, and then pass call its method to download synchronously with parameter self as delegate. Then from internetdownload class I call delegate(internetImageReady) again with self.
I couldn't figure out other model and neither could remove its leaks.
The variable will only be nil before ever being assigned or if you manually set it to nil. Simply releasing the variable, even if it is deallocated, will not set the pointer back to nil. If you really want to do something only if the variable is deallocated you can check the retain count before releasing it (if you do it after you may get a message send error). But normally you should just release it and then reassign it because it not being deallocated assumes that some other piece of code is still using it (if you are retaining and releasing correctly).
That doesn't make any sense. If the retain count is zero, then the object either doesn't exist or won't exist for very much longer, and if the retain count is non-zero (which is about the only useful info you can get from the retain count), then the object does exist. That's not really any different than what he's already doing.
You are correct that releasing it beforehand doesn't mean it is now nil, but that doesn't invalidate the test. He could, and possibly should, assign nil to the property at a later point in the program. And there is virtually nothing that should be coded against a retain count. That's just plain risky.
That doesn't make any sense. If the retain count is zero, then the object either doesn't exist or won't exist for very much longer, and if the retain count is non-zero (which is about the only useful info you can get from the retain count), then the object does exist. That's not really any different than what he's already doing.
You are correct that releasing it beforehand doesn't mean it is now nil, but that doesn't invalidate the test. He could, and possibly should, assign nil to the property at a later point in the program. And there is virtually nothing that should be coded against a retain count. That's just plain risky.
Yes you are right. I do not suggest using the retain count as a test, it is the only thing I could think of if he really wanted to do something only when deallocating it. The test is definitely not invalid it will still run for sure. I just know that it took me a little while to realize that it wasn't doing what I wanted it to do (i have done similar things in my code). I tried to write that code when I was releasing something and then only wanted to reassign it if the object was no longer assigned. I just wanted to make sure that he realized what it was doing. With that code he is only going to alloc the variable once, not every time the code is run (unless he resets the variable to nil somewhere else and then the release is worthless.
Thanks for the reply.
That really make sense and I am already done with the code changes you suggest after revisiting some of memory management articles. Unfortunately I m still getting leaks of UIImage and InternetImage(class for asynchro download image). I really dont know where to release this object.
I alloc and init its(InternetImage) object every time user press next or previous, and then pass call its method to download synchronously with parameter self as delegate. Then from internetdownload class I call delegate(internetImageReady) again with self.
I couldn't figure out other model and neither could remove its leaks.
Do you think that you could post up your revised code so that it is a little easier for me to look at?
Do you think that you could post up your revised code so that it is a little easier for me to look at?
I solved rest of the glitches myself. I have been assigning properties with equal(=) operator. Changing it with call to its setter method like [self setNextimg:tempnextimg] solved most of the my problems. On most of the places I was releasing assigned variables after assigning to the properties. So properties were also releasing from memory. I thought both have the same meanings but I guess assigning variable to properties with equal operator means copying pointer and memory allocation remains the same whereas assigning it with its setter method would allocate another memory location and assign.
Please correct me if I m still mistaken. Second thing I m confused, whether assigning nil to property is equal to releasing it or not.
I solved rest of the glitches myself. I have been assigning properties with equal(=) operator. Changing it with call to its setter method like [self setNextimg:tempnextimg] solved most of the my problems. On most of the places I was releasing assigned variables after assigning to the properties. So properties were also releasing from memory. I thought both have the same meanings but I guess assigning variable to properties with equal operator means copying pointer and memory allocation remains the same whereas assigning it with its setter method would allocate another memory location and assign.
Please correct me if I m still mistaken. Second thing I m confused, whether assigning nil to property is equal to releasing it or not.
Thanks to everyone for their response.
Regards,
I'd say you got it.
Assigning any new value to a property, whether nil or otherwise, releases the old value. You only want to release properties in dealloc.
I solved rest of the glitches myself. I have been assigning properties with equal(=) operator. Changing it with call to its setter method like [self setNextimg:tempnextimg] solved most of the my problems. On most of the places I was releasing assigned variables after assigning to the properties. So properties were also releasing from memory. I thought both have the same meanings but I guess assigning variable to properties with equal operator means copying pointer and memory allocation remains the same whereas assigning it with its setter method would allocate another memory location and assign.
Just to clarify one thing here, the following two statements are identical and do the same thing memory management-wise:
Code:
someObject.someProperty = someValue;
// is exactly the same as:
[someObject setSomeProperty: someValue];
Some people prefer the latter syntax. I prefer the former. But either way, they are the same thing.
One little thing I do to avoid accidentally making direct assignment to an ivar without using the setter, is that I don't name the ivar exactly the same as the property. I usually just put an underscore before it. So like this for example:
Code:
// in the interface:
NSString* _name;
@property (nonatomic, copy) NSString* name;
// then in the implementation:
@synthesize name = _name;
// then the compiler will catch if I accidentally try to do this:
name = someString;
// when I really meant to do this:
self.name = someString;