I'm getting memory leak problem in this code:
UIImage myImage1 = [[UIImage alloc]
initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:strimg1]]];
How can I solve this problem?
Thanks in advance.
UIImage *myImage1 = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:#""]]];
UIImageView *myimg=[[UIImageView alloc] initWithImage:myImage1];
[self.view addSubview:myimg];
[myimg release];
it may helps you.
Remember that whenever you create an an Object using New or Alloc init,
it is your responsibility to release it in the dealloc. and remember to used super dealloc.
Make sure no other object bump the retain count.
What is in the init method? Did you create another instance of class UIImage? Just a thought.
Hope this help. dibu2z
Related
This is my code in my application,
[imageview setAlpha:1.0f];
[imageview setImage:[UIImage imageNamed:[NSString stringWithFormat:#"%#.png",[pages objectAtIndex:swipeCount]]]];
[imageview setFrame:CGRectMake(-300, 0, 1368, 1000)];
Edit:
pages = [[NSArray alloc] initWithObjects:#"page1",#"page2",#"page3",#"page4",#"page5",#"page6",#"page7b",#"page8",#"page9",#"page10a",#"page11",#"page12",#"page13b",#"page14",#"page15",#"page16a",#"page17",#"page18",#"page19",#"page20",#"page21",#"page22",#"page23",#"page24",#"page25", nil];
imageview=[[UIImageView alloc]init];
its working properly, problems except when the app enters background and comes back to foreground shows the following error,
*** -[UIImage isKindOfClass:]: message sent to deallocated instance 0x1e8b10
What wrong with the code?
Please help me out
Yes, you need to allocate memory to your UIImage. What is basically happening is that your image is being temporarily stored in the memory and deallocated upon closing the app so iOS could allocate that memory to more immediate needs. You can fix that as below. I'm also gonna allocate a string since stringWithFormat returns an autorelease String.
NSString *imageName = [[NSString alloc] initWithFormat::#"%#.png",[pages objectAtIndex:swipeCount]];
UIImage *myImage = [UIImage imageNamed:myImage];
[imageview setImage:image];
Try using properties. Make array,imageView as a property and then use
self.pages and self.imageView
see this good article on properties
Objective-c properties
I m loading lots of rather large images in my viewcontroller, using
NSUInteger nimages = 0;
for (; ; nimages++) {
NSString *nameOfImage_ = #"someName";
NSString *imageName = [NSString stringWithFormat:#"%#%d.jpg", nameOfImage_, (nimages + 1)];
image = [UIImage imageNamed:imageName];
if (image == nil) {
break;
}
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
//some other stuff....
[imageView release];
}
the usual unloading occurs in - (void)viewDidUnload and - (void)dealloc
with self.image = nil; and [image release];
It seems after a few "loading" and "unloading" the cache still grows to the point of no return!!
:)
and the app crashes...
any ideas??? how do i empty my cache? and where?
thanks
EDIT:
ok this is what i was doing wrong.
Apparently this piece of code fixes the whole caching problem:
image = [[UIImage imageNamed:imageName] autorelease];
with autorelease being the key here.
thanks for the replies...
Thank you all for your suggestions.
Solution:
Used ARC and imageWithContentsOffFile to initialize the Images.
image = [UIImage imageWithContentsOfFile: [[NSBundle mainBundle] pathForResource:imageName ofType:nil]];
And Yes, imageNamed is only good for... well for nothing big...
image = [[UIImage imageNamed:imageName] autorelease];
This is incorrect. In keeping with the memory management rules, you shouldn't be releasing (or autoreleasing) the image because you didn't allocate or retain it. "imageNamed" doesn't contain "alloc", "new", "copy", or "retain".
As some of the other answers explain, you should load your images with a different method if you want more control over the memory they use.
imageNamed is an awful way to load images in reality, it never releases loaded images unless forced and keeps them in the cache forever. You should implement your own, more intelligent cache. A simple NSMutableDictionary gives the same functionality but with more flexibility.
For a more in-depth discussion you can read this: http://www.alexcurylo.com/blog/2009/01/13/imagenamed-is-evil/
Use another method to initialize you image. imageNamed caches.
Instead of using using imageNamed you can use imageWithContentsOfFile:
Or check this article
link 0
link 1
[[UIImage alloc] initWithContentsOfFile:path]
return nil when the method can't initialize the image. Then next code is not releasing the allocated UIImage, as image is nil in the [image release] line:
UIImage* image = [[UIImage alloc] initWithContentsOfFile:path];
if(image)
{
....
}
//Here image is nil and not releases allocated UIImage.
[image release];
Is this really a memory leak?
if init returns nil, how must release the object?
if I do
UIImage* image = [[UIImage alloc] initWithContentsOfFile:path];
and image is nil because init fails,
[image release] is the same as [nil release]. Ok there's not an error, but is not releasing anything.
Retain count in this example has nothing to do with whether or not the image is nil. You manually allocated the image using
UIImage* test = [UIImage alloc];
and therefore the retain count will be one until you manually release it, as you are the sole owner of that object.
See Memory Management Rules for more information on the subject.
release on nil is a no-op, so always ok. And it won't leak as you didn't have an object to start with.
UIImage* test = [UIImage alloc];
test is already an UIImage object on its own (though you failed to initialize it at this line).
You really should always do alloc/init on the same line (and on the same variable) - or the code logic is really hard to follow. Your code generates only one object, and then assigns it to another variable.
This is the same, though much clearer:
UIImage* test = [[UIImage alloc] initWithContentsOfFile:path];
UIImage* image = test;
int n = [test retainCount]
Here it is obvious that test and image are the same object (and hence have the same retainCount). Whenever you release one of them, the the object goes away (unless you retain it before).
Please also note that retainCount is not something you should rely on or make much assumptions on. It often is misleading at best.
I'm trying to use a url as a UIImage in the OpenFlow API.
NSString *imageUrl = [[[newsEntries objectAtIndex:0] objectForKey: #"still"] retain];
NSURL *url2 = [NSURL URLWithString:imageUrl];
NSData *photoData = [NSData dataWithContentsOfURL:url2];
UIImage *imageUI = [UIImage imageWithData:photoData]
UIImageView *myImage = [UIImageView initWithFrame:imageUI];
[(AFOpenFlowView *)self.view setImage:[UIImage imageNamed:myImage]];
[imageUr release];
[(AFOpenFlowView *)self.view setNumberOfImages:3];
I have tried it like this, but no success. The only way I got this API working was using the imageNamed type. The initwithData has no success.
So how can I change this NSString to finally become a imageNamed method?
A UIImageView is different from a UIImage.
Change this line: [(AFOpenFlowView *)self.view setImage:[UIImage imageNamed:myImage]];
To this: [(AFOpenFlowView *)self.view setImage:[UIImage imageNamed:imageUI]];
and it should work.
You have several significant errors here. It appears that you may need to read about C/Objective-C and types.
It sounds like you are asserting that, specifically, the line
UIImage *imageUI = [UIImage imageWithData:photoData]
is not working. The code up to that point actually looks okay (though it is not necessary to retain and then release the imageUrl variable.
Once you have created your UIImage, you should be able to pass it directly to your AFOpenFlowView:
[(AFOpenFlowView*)self.view setImage:imageUI forIndex:0];
The line
UIImageView *myImage = [UIImageView initWithFrame:imageUI];
has two errors (and is unnecessary anyway). First, -initWithFrame takes a CGRect as its argument, not a UIImage. UIImageView does have an initialization method -initWithImage, which is probably what you intended. But either way, methods that start with "init" are instance methods, not class methods, so you have to call them on actual instances of a UIImageView, like this:
UIImageView *myImage = [[UIImageView alloc] initWithImage:imageUI];
Note that this will leak memory unless you autorelease or release it.
The following line, you correctly try to give a UIImage to your AFOpenFlowView, but you attempt to create that UIImage by passing a UIImageView to the +imageNamed method. +imageNamed takes an NSString that contains the name of the image, and passing anything else to it won't work.
You must always be aware of what kind of object a method is expecting to receive, and make sure you find some way to give it that kind of thing.
Probably what you are looking for here is something like this:
NSString *imageUrl = [[newsEntries objectAtIndex:0] objectForKey: #"still"];
NSString *imageName = [imageUrl lastPathComponent];
[(AFOpenFlowView *)self.view setImage:[UIImage imageNamed:imageName]];
Instruments' Leaks tells me that this UIImage is leaking:
UIImage *image = [[UIImage alloc] initWithContentsOfFile:[imagesPath stringByAppendingPathComponent:[NSString stringWithFormat:#"/%#.png", [postsArrayID objectAtIndex:indexPath.row]]]];
// If image contains anything, set cellImage to image. If image is empty, try one more time or use noImage.png, set in IB
if (image != nil){
// If image != nil, set cellImage to that image
cell.cellImage.image = image;
}
image = nil;
[image release];
(class cell (custom table view cell) also releases cellImage in dealloc method).
I haven't got a clue of why it's leaking, but it certainly is.
The images gets loaded multiple times in a cellForRowAtIndexPath:-method. The first three cells' image does not leak (130px high, all the space avaliable).
Leaks gives me no other info than that a UIImage allocated here in the code leaks.
Can you help me figure it out? Thanks :)
The code you have there would be correct if image was a #property. You can release a #property by doing self.property = nil because of the way the setter works. The setter releases the old object and sets the ivar to the value. In order to fix this you would need to put [image release] first. What is happening here is that you set image to nil and then you are essentially doing [nil release]. The old image is just floating around somewhere. So to fix this do the following:
[image release];
image = nil;
You are setting it to nil before calling release. So you are releasing nil instead of image.
Change from:
image = nil;
[image release];
to:
[image release];
image = nil;
Little bit code modification
UIImage *image = [[UIImage alloc] initWithContentsOfFile:[imagesPath
stringByAppendingPathComponent:[NSString stringWithFormat:#"/%#.png",
[postsArrayID objectAtIndex:indexPath.row]]]];
if (image){
cell.cellImage.image = image;
[image release];