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];
}
Related
I have written code that when you hit button, it opens new screen with image on it. On that new screen there is button that dismisses screen, and returns to main screen. And it works fine if i do it like this (no leaks etc...):
img = [UIImage imageNamed: #"Galaxy"];
ImageDisplay *display = [[ImageDisplay alloc] initWithImage:img];
But if i replace this line of code with something like this:
img = [[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"Minnesota" ofType:#"png"]];
ImageDisplay *display = [[ImageDisplay alloc] initWithImage:img];
[img release];
It acts as i have memory leak. Every time i open image screen, app takes more and more memory. But all deallocs are called, even [img retainCount] shows 1 before final release. Is there possibility that there is a bug here, because i cant find whats wrong?
EDIT:
Here is dealloc method for ImageDisplay, and this method gets called:
-(void) dealloc {
[img release];
[super dealloc];
}
Your ImageDisplay *display is retaining the image. As it should be. When you release that, it should release all its retained entities. In the code you've shown, you're not releasing it. The typical use would be to tell the containing view controller to display it modally or something (or push it onto a navigation controller) and release it, leaving its retain lifecycle in the hands of whatever view controller is now managing it. The difference is, in your first code sample, *img is autoreleased, and will release itself when appropriate, and in the second, it's not.
ARC would save your bacon here, and dramatically simplify your code.
Also you should google the term "static method", because you're working really hard to call static methods as instances of the class of objects, which is like going around your ass to get to your elbow.
ALSO, stop looking at retainCount. All sorts of things might retain your objects under the hood of the framework. Using retainCount as part of your debugging strategy is a one way ticket to confusionville.
Try using this one instead, you dont need to allocate and release:
[UIImage imageWithContentsOfFile:(NSString *)name]
Note that since imageNamed: is a class method not an instance method, you use it like this:
UIImage *myImage = [UIImage imageNamed:#"pony.png"];
Your posted code using initWithContentsOfFile looks correct, so the leak must be somewhere in your ImageDisplay class.
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.
what is the best method to display about 300 png images into a UITableView..
i dont wanna display them at the same time... i have 3 tableViewControllers that will each display about 100 imgaes.. (its for a catalog so the images are important to display)
i used [uiimage imageNamed:] but that method caches the images and they dont get released so the memory usage is big.... is there any way to release the cache when the nav controller pushes a different view controller?
i also tried [uiimage alloc] initWithContentsOfFile] but the images wont display....
any help?
[UIImage imageNamed:#"foo.png"];
is equivalent to
[[[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"foo" ofType:#"png"]] autorelease];
except it does not cache the image.
If you write your own caching function, you can purge it at any time. When you need an image, check an NSMutableDictionary by name. If it does not exist, load the image normally and add it to the dictionary with the name as a key. To flush the cache, remove all objects from the dictionary.
To quote from the CGLayer doc:
Quartz caches any objects that are reused, including CGLayer objects.
I am having problems with memory on large pages and am trying to implement a simple mechanism where views are released and recreated based on whether they are on/off screen.
Say for the sake of simplicity that I have a bunch of UIImages, created as the result of a network request, saved in an array somewhere. I create a UIImageView like so:
anImage = [anArray objectAtIndex:0];
UIImageView* imgView = [[UIImageView alloc] initWithImage:anImage];
[mainView addSubview:imgView]; // Quartz eats memory for view after first draw
[imgView release]; // owned by mainView now
[...] // wait a bit for draw cycle
[imgView removeFromSuperview]; // memory doesn't go down
When the imgView goes offscreen it is removedFromSuperview and released. Fine right? Nope- the CGLayer that exists in Quartz is not removed, because anImage still exists.
How can I get around this? The only way in this scenario is to create an image exactly the same behind Quartz's back with a different pointer address and delete the old image. And the only way to do this is to 'deep copy' the image (UIImage doesn't implement NSCoding) or to ask for it again over the network (slow).
What I am thinking is that I need to sqllite my images to a database and refetch them every time a view comes onscreen- but I would love to hear people's thoughts on this.
Here you increment imgView from 0 to 1.
UIImageView* imgView = [[UIImageView alloc] initWithImage:anImage];
In the next line, the mainView incrementes the reference count. (now it's 2)
[mainView addSubview:imgView]; // Quartz eats memory for view after first draw
Here, you release the imgView and the reference count goes back down to one.
[imgView release]; // owned by mainView now
I don't think your memory issues have anything to do with anImage. As long as imgView is a subview, it won't free that object, because it needs that object to draw to the screen.
What the following line means, is that if you programmatically draw to your CGLayer, Quartz with cache what you've drawn, so that you aren't constantly redrawing the same thing. It's not really related to adding subViews.
Quartz caches any objects that are reused, including CGLayer objects.