★ TouchArcade needs your help. Click here to support us on Patreon.

UIImage and memory- help please

03-19-2009, 12:11 PM
#1
Joined: Sep 2008
Location: Birmingham, UK, dull corner of the world
Posts: 2,367
UIImage and memory- help please

I am trying to work out allocating and de-allocating memory, and just can't seem to get it right for the purpose I want.
Basically, I am using UIImage to display in-game animation and also extras such as Instructions. For example, as I only have a few instructions pages, when tapping on the Instructions button, I un-hide an instructions UIButton, which fills the screen and allows you to tap it to go to the next page, and hides again after the last one (I didn't think it was worth setting up a seperate ViewController class just for a few pages of info).
To concerve memory, what I'd ideally like to do is load the images all together when needed, then have them de-allocated when finished with (so when a game is finished and you return to the menu, the in-game characters will be de-allocated, and the same for the instructions after the last page is displayed). Then of course, I'd load up a new set only when needed again. This would be helpful for the game section mostly, as different PNG's might be loaded for each game. So I want them de-allocated at the end of play to make room for new ones. However, it would be useful for other sections such as the instructions pages too.

Anyway, unfortunately, I have 2 books and can't find ANYWHERE in either one, any tutorial on getting PNG's into memory, displaying and/or animating them, then de-allocating them. My one book "Beginning iPhone Development" uses "UIImage imageNamed" to load images into the project, and they warn that it is a "convenience class" which uses the autorelease pool. But that is the ONLY way I know to load images as that's the only way it flippin' shows me!!!

Attached is a sample of my code (it is the method that is called when you either tap the instructions button in the menu, or tap the instruction page button if it is already displayed). It loads the instruction pages into an array, and I call on the objects in the array to then display the appropriate page. You can see I try to allocate memory to the image and then de-allocate later, but I know it isn't working properly when I use NSLog to display the retain count, which seemingly gets confused by the "UIImage imageNamed" command, which ties in with what my book said about it.

But like I said, I don't know of any other way, thanks to these two "tutorial" books not telling me. Could someone please look over the code to see if it is the right way to go about it, and perhaps tell me a way to load images in so they can be released manually? Thank you.

What's really annoying me is my game doesn't crash at all now, except for when I access the instructions, and I get a 101 error, which is memory related.
Attached Thumbnails
Click image for larger version

Name:	Picture 1.png
Views:	15
Size:	19.8 KB
ID:	1871  

Last edited by wastedyuthe; 03-19-2009 at 12:17 PM.
03-19-2009, 12:23 PM
#2
Joined: Mar 2009
Location: Hanover, NH
Posts: 17
Have you tried using the imageWithData way instead?

http://stackoverflow.com/questions/3...-imagewithdata

03-19-2009, 12:29 PM
#3
Joined: Sep 2008
Location: Birmingham, UK, dull corner of the world
Posts: 2,367
Quote:
Originally Posted by allenp View Post
Have you tried using the imageWithData way instead?

http://stackoverflow.com/questions/3...-imagewithdata
Ah! Reading some of the response on that...

"On the other hand, if you have a very large image and you're not re-using it, you might want to load the image from a data object to make sure it's removed from memory when you're done.
If you don't have any huge images, I wouldn't worry about it."

This sounds like it could be the ticket, as my instruction pages and my in-game PNG's are very large indeed. So would I use "alloc" and "init" commands on both the NSString and NSData variables first, allowing me to "release" them after adding the image to an array?

[UPDATE] I have implemented the new code into my loop now, and can get it to work so long as I don't try allocating and releasing objects, which results in the console displaying the second picture attached to this post. The first picture shows the new loop. Could someone please tell me where I can insert the alloc and release commands so it won't crash? Thanks.

Attached is a piccy of the new code inserted into the loop from my first post. What am I doing wrong? (this is before even adding commands to allocate and release memory!)
Attached Thumbnails
Click image for larger version

Name:	Picture 2.png
Views:	15
Size:	18.4 KB
ID:	1877   Click image for larger version

Name:	Picture 3.png
Views:	8
Size:	71.2 KB
ID:	1878  

Last edited by wastedyuthe; 03-19-2009 at 01:55 PM.
03-19-2009, 03:25 PM
#4
Quote:
Originally Posted by wastedyuthe View Post

[UPDATE] I have implemented the new code into my loop now, and can get it to work so long as I don't try allocating and releasing objects, which results in the console displaying the second picture attached to this post. The first picture shows the new loop. Could someone please tell me where I can insert the alloc and release commands so it won't crash? Thanks.

Attached is a piccy of the new code inserted into the loop from my first post. What am I doing wrong? (this is before even adding commands to allocate and release memory!)
FYI, not seeing any exceptions in that console screenshot..
03-19-2009, 03:28 PM
#5
Joined: Sep 2008
Location: Birmingham, UK, dull corner of the world
Posts: 2,367
Quote:
Originally Posted by lithiastudios View Post
FYI, not seeing any exceptions in that console screenshot..
I know. But the game freezes in the simulator at the point the console reports that. I am wondering why it displays it, but I assume it's because I have done something wrong when I attempt any manual releasing. When I remove alloc and release commands the instructions work perfectly and the console doesn't report anything.

Last edited by wastedyuthe; 03-19-2009 at 03:31 PM.
03-19-2009, 04:04 PM
#6
Quote:
Originally Posted by wastedyuthe View Post
I know. But the game freezes in the simulator at the point the console reports that. I am wondering why it displays it, but I assume it's because I have done something wrong when I attempt any manual releasing. When I remove alloc and release commands the instructions work perfectly and the console doesn't report anything.
I'm still coming to grips with Obj-C memory management, but maybe it has to do with you releasing the Array and then releasing one of the objects in the array? As when you add an object to a NSMutableArray, it adds a reference to that object. Maybe when you're releasing that Array that reference is gone, and then the retain count is messed up?

When you remove an object from an Array, the NSMutableArray releases that object.. so maybe try this:

[instructions removeAllObjects];
[instructions release];

instead of:
[instructions release];
[drawInst release];
03-19-2009, 04:51 PM
#7
Joined: Sep 2008
Location: Birmingham, UK, dull corner of the world
Posts: 2,367
Quote:
Originally Posted by lithiastudios View Post
[instructions removeAllObjects];
[instructions release];
I have added the two lines quoted to the method and that seems to run just fine, thanks! (picture of new code attached with your lines at the bottom end)

So, I have released the 'instructions' array at the end- but also have drawInst UIImage and fileLocation (used for the file path) allocated and initialized at the start. With your previous post, are you saying I don't need to release drawInst as releasing the array will do that? Are there any other allocations or releases I can put into my code to optimize it?

Thanks very much for your help so far.
Attached Thumbnails
Click image for larger version

Name:	Picture 4.png
Views:	9
Size:	24.8 KB
ID:	1884  
03-19-2009, 05:05 PM
#8
Quote:
Originally Posted by wastedyuthe View Post
I have added the two lines quoted to the method and that seems to run just fine, thanks! (picture of new code attached with your lines at the bottom end)

So, I have released the 'instructions' array at the end- but also have drawInst UIImage and fileLocation (used for the file path) allocated and initialized at the start. With your previous post, are you saying I don't need to release drawInst as releasing the array will do that? Are there any other allocations or releases I can put into my code to optimize it?

Thanks very much for your help so far.
So now you have:

drawInst = [[UIImage alloc] init];

then

[instructions addObject:drawInst];

at this point retainCount for drawInst is 2, correct? (I see you have a NSLog there, so you can verify that.. )

Doing a removeAllObjects should do a release of drawInst.. but that would bring your retainCount to 1. I think you still need to match a release with the initial alloc.

The general pattern is that you should have as many releases as you do alloc + inits. So you need to add a release for fileLocation somewhere.

From what I've read helper functions "xWithy" will do a autorelease for you. So I'm not sure you need to add any releases for those.

Like I said earlier, I'm still coming to terms with memory management myself, so take this all with a grain of salt. I'd confirm what I'm saying with some NSLog statements.
03-19-2009, 05:39 PM
#9
Joined: Sep 2008
Location: Birmingham, UK, dull corner of the world
Posts: 2,367
Quote:
Originally Posted by lithiastudios View Post
at this point retainCount for drawInst is 2, correct? (I see you have a NSLog there, so you can verify that.. )

Doing a removeAllObjects should do a release of drawInst.. but that would bring your retainCount to 1. I think you still need to match a release with the initial alloc.

The general pattern is that you should have as many releases as you do alloc + inits. So you need to add a release for fileLocation somewhere.
Yes, it has a retainCount of 2 at that point. However, I have tried to release drawInst again, and this is where I come up with issues and I really get confused as to why I am having them. Attached with this post is the code (first pic) with added NSLog commands as well as the new [drawInst release]; command, which I have tried before and after the [instructions release]; commands. The second piccy attached is of the console report. You can see the two times I have gone through my instructions pages. The first time goes through as expected, but ending with a retain count of one. When I run through the instruction pages again, it lets me go through all five pages again, but crashes when I tap the last one to return to the main menu. As you can see on the console report, it comes up with the same thing as in my previous piccy at that point.
So, noticing I end up with a retainCount of 1, I added yet another [drawInst release]; command in the same place as the first (pic No 3), only it crashed after the 5th page on the first attempt this time, not the second. I really don't get this at all. I thought if something has a retain count of 1 and you release it when not used anymore, then that would be fine. I'm getting a headache.
Attached Thumbnails
Click image for larger version

Name:	Picture 1.png
Views:	5
Size:	28.6 KB
ID:	1885   Click image for larger version

Name:	Picture 2.png
Views:	2
Size:	77.2 KB
ID:	1886   Click image for larger version

Name:	Picture 3.png
Views:	1
Size:	68.5 KB
ID:	1887  

03-19-2009, 06:13 PM
#10
Joined: Dec 2008
Posts: 439
You have

drawInst = [[UIImage alloc] init];

But then later you have

drawInst = [UIImage imageWithData....

this causes the initial uiimage you allocated to leak... because you're creating a new uiimage object in the second line...

If you want to allocate and release... leave off that first line... and don't use imageWithData... because that uses autorelease also...

If you want to allocate and deallocate yourself... you should allocate and deallocate inside your for loop... allocate at the beginning... deallocate at the end...

drawInst = [[UIImage alloc] initWithContentsOfFile....

or drawInst = [[UIImage alloc] initWithData...

and have a [drawInst release] at the end of the for loop.

look here for the method descriptions:
https://developer.apple.com/iphone/l...ontentsOfFile: