I'm developing an app for iPhone using a coverFlow view, when the app is building the cards it is using a UIView in order to add labels and other stuff. Then I convert the UIView into UIImage using the following code:
UIGraphicsBeginImageContext(imageView.bounds.size);
[imageView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// returning the UIImage
return viewImage;
Every Time I redraw the coverflow I have a huge memory allocation increment, that never decreases even if I dealloc my coverFlow view.
I think the memory leak is in the code that I added, what do you think?
There is no memory leak apparent in the code snippet you provided. That operation could not be performed on a background thread because of UIGraphicsBeginImageContext(), so you should have an NSAutoreleasePool in place (the return value of UIGraphicsGetImageFromCurrentContext() is autoreleased). Without further information, its impossible to tell where the memory leak could be - I suggest you look at whatever objects eventually own the viewImage object and make sure you are properly releasing the UIImage if you retain it.
Use drawViewHierarchyInRect:afterScreenUpdates: instead of renderInContext: it is 15x faster.
You can see the comparison on this article.
Also, I have created a Swift extension for doing this: https://stackoverflow.com/a/32042439/517707
Related
Hi every one I have the next issue I'm creating various images like this
UIImage *image = [UIImage imageNamed:_imageName];
and I'm assigning to one UIImageView
[self.imgvImage setImage:image];
The user when tap a button one UIImageView is created and one UIImage is assigning, I have 4 UIImageViews created when new is created the last is removed sending release to the UIImageView like this
[_imgvImage release];
But around than 100 times creating and releasing one memory warring happen but the app dont crash I think this is because the UIImages created are not releasing and there are so much because all the code are clean and creating and releasing are all fine.
How can I remove all the UIIMageView with his UIImage completely from the memory.
Please help, sorry for my English in not good.
The image created using below statement is handled by iOS. this image is stored in a cache so that next time you call this it is simply get returned from the cache.
UIImage *image = [UIImage imageNamed:_imageName];
I think you should not worry about memory warning as long as you are releasing what you are allocating (UIImageView in this case). iOS should clear this cache in case of memory crunch.
If you do not want that caching (e.g. when you are loading one image once only) you can use imageWithContentsOfFile: method of UIImage.
Hi I found the solution the solution was call the
NSAutoreleasePool
in the method when I removed the objects of the view like this:
for(ProductVW *pVW in [_vwProductsContainer subviews]){
NSAutoreleasePool * autoreleasePool = [[NSAutoreleasePool alloc] init];
[pVW removeFromSuperview];
[autoreleasePool release];
}
UIImageView *mooshinLogo = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"mooshin.png"]];
I'm not sure if im instantiating my image correctly because i've been reading that imageNamed will not be emptied from the cache and should only be used for buttons and small icons. What about background images, and image galleries?
How do I implement UIImageView the right way?
imageNamed: method caches images that you load. In case of low memory conditions or memory warning that cache will be emptied.
If you want to show images in gallery it is better to use imageWithContentsOfFile: method as it doesn't cache the data.
In case of very big images you should use CATiledLayer to display your image using tiles.
No worries! The method imageNamed returns an autoreleased object, and it will do what you call "be emptied from cache" (i.e. its memory will be released) when it is not needed any more.
[UIImage imageNamed:(NSString *)imageName] is an autorelease convenience constructor. This means that it's retain count is increased when you initialize it and decreased at the end of the runloop. You could make 100 of them and they'd vanish from memory a few seconds later, unless they're retained by something else. By passing it to the UIImageView, the UIImageView will retain it and it will stay in memory only until the UIImageView is done with it, so you're doing that correctly, unless you're referring to the OS caching the image in "inactive" RAM. It may do that behind the scenes (and will know when to get rid of it), but you're certainly handling the object's lifecycle correctly. Since you're using the [[Class alloc] init...] way to construct your UIImageView, make sure you later call [mooshinLogo release] or [mooshinLogo autorelease].
(Please just ignore this if you already know.) Objective-C (at least, for iOS development) is a reference counted language. All objects start out with a reference count, or retain count, of 1, from the time they are alloc'd. From there, they can be retained ( [id retain] ), released ( [id release] ), or marked to be released at the end of the runloop ([id autorelease] ). Once the count is zero, they will be dealloc'd, but you should never concern yourself with it's actual retain count and only use objects you own (or are retaining).
When in doubt, you can check with Clang's Static Analyzer. It's finds probably 75% of the your leaks, and I've only had a handful of false positives. Either Build & Analyze, or Cmd+Shift+B.
Others above are right about imageNamed keeps a cache of these images. This is especially true when using NIB files. Releasing a Viewcontroller with ImageViews on them doesn't directly release the associated images.
I had an app that had lots of images with lots of pages in a navigation controller. Eventually it would crash when only using imageNamed method. So, I now use (found here on SO) and over:
+ (UIImage *)imageNamed:(NSString *)name {
//NSLog(#"ImageNamed: %#", name);
return [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:name ofType:nil]];
}
Now I can control when I want to remove an image and and make it actually clear from memory. The aforementioned app, I would actually load the images on viewDidLoad and remove them on viewDidDisappear. So, when I was 10-15 pages deep in the NavController, I could keep memory down.
i´ve created a little game in which images are loaded when the user is touching the screen while moving. It depends on the screen position to load different images immediately.
I´ve got an UIImageView and because within the "touchesMoved" function, i´m loading the different images like this:
imageView.image = [UIImage imageNamed: [photos objectAtIndex: newImage ] ] ;
Now i want to improve my memory management using Instruments with "Allocations" & "Memory Monitor". Here´s i´m setting different snapshots with "Mark Heap" points and look for leaks. The line above is highlighted and now i want to know what´s wrong with it.. How can i improve that image-loading (without caching)?
Read this Dispelling the UIImage imageNamed: FUD
and also read the links in the question as well. Should answer everything you need.
First of all: imageNamed: does cache images.
If you're getting this line highlighted then there are 2 possible reasons (or both):
you're not properly releasing imageView
you're not properly releasing the photos array
+imageNamed returns an autoreleased object, yet the #property image in UIImageView retains it through its use until overwritten. -objectAtIndex: must return an object with a retain count of 1 which is not released.
If that indeed is the problem then the fix is
imageView.image = [UIImage imageNamed: [[photos objectAtIndex: newImage ] autorelease]];
However I doubt that is the real issue here.
I currently have this code:
UIImage *image = [[UIImage alloc] initWithContentsOfFile:[imagesPath stringByAppendingPathComponent:[NSString stringWithFormat:#"/%#.png", [postsArrayID objectAtIndex:indexPath.row]]]];
It's loading in an image to set in a UITableViewCell. This obviously leaks a lot of memory (I do release it, two lines down after setting the cells image to be that image), and I'm not sure if it caches the image at all.
Is there another way, that doesen't leak so much, I can use to load in images multiple times, like in a tableView, from the Documents-directory of my app? Thanks.
The leaks tool or Instruments should tell you what exactly is leaking. However, the image and imageView properties retain their images, so you may need to ensure you're properly releasing them in the dealloc method for the UITableViewCell. But like AngeDeLaMort said, we really need more information to give you a precise answer.
What is leaking exactly?
If you alloc an image and release it after, I don't see the leak your are talking about? Maybe more code or more precision would help.
I'm using the following code:
UIImage *buttonImage;
if (p.placeImage != nil) {
buttonImage = [UIImage imageWithData:p.placeImage];
} else {
buttonImage = [UIImage imageNamed:#"bg_place_noimg.png"];
}
[imageButton setBackgroundImage:buttonImage forState:UIControlStateNormal];
When executing the app with Instruments I can see the setBackgroundImage consumes a lot of memory. However, if I comment the last line it doesn't happen. Any possible reason?
EDIT:
If p.placeImage == nil and imageNamed:#"bg_place_noimg.png" is used memory usage is normal. p.placeImage is a Transformable value I use in Core Data to store images NSData downloaded from Internet.
I'm not surprised that commenting out the last line causes less memory to be consumed. When you set that image as the background of your button, the image is most likely retained by the button and so the image remains in memory. If you don't apply the image as the button background, the UIImage's retain count is 0 and so its memory can be reclaimed by the system if necessary.
Kristopher's theory about the difference between imageWithData and imageNamed is also correct. Check out the Discussion section for each of those initializers in the documentation for UIImage.
I'm not sure, but I would guess that your problem is that imageWithData: creates a whole new image each time, whereas the imageNamed: method returns the same image over and over again.
You may need to add some code to cache and reuse images that are identical. For example, maybe you could use a URL as a key into a dictionary of images, and only create new images for URLs that have not been loaded before.