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.
Have you tried using the imageWithData way instead? http://stackoverflow.com/questions/316236/uiimage-imagenamed-vs-uiimage-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!)
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];
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.
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.
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/library/documentation/UIKit/Reference/UIImage_Class/Reference/Reference.html#//apple_ref/occ/instm/UIImage/initWithContentsOfFile:
I will tinker more and change the commands to what you suggest- I didn't realize imageWithData used autorelease too. Again, thank you very much for your assistance. Much appreciated. [UPDATE] I changed commands to your suggestion and there seems to be some improvement during the loop, where the retainCount amount stays at 1 through each loop. However, the final retainCount stood at 2 when returning to the main menu. However, clicking the instructions button again reverted back to a count of 1 through the loop again and there is no crashing. Again, I am getting confused, as because it ends with a retainCount of 2, I decided to add another [drawInst release]; command at the end to at least take it down to 1 (pic 1). This does indeed work, as you can see by the console result in pic 2. However, when returning to the main menu and clicking the instructions button again, it goes through the loop (again, you can see the loop NSLogs in the console) and then crashes, again with the same results as before. How is this ever supposed to deallocate when it keeps crashing when it gets anywhere close to 0?
Sorry for the double post- but I wanted everyone who helped to know that I have got it sorted. I used the new commands, but still couldn't get it to release the last retainCount without crashing. Then it hit me- all I do after the last page is displayed is HIDE the instructions. So it crashes because I am trying to deallocate something that is still being used, it's just hidden that's all. So, before releasing the array, I set the image of the button back to the first page of instructions using "UIImage imageNamed" rather than the array- THEN release the array, and it gets successfully deallocated! Attached is my final code (pic 1) and proof it works from the ObjectAlloc instrument (pic2- you can see where the app loads and main menu displays when the blue bar starts, then it increases as each instructions page is displayed, then returns to the same level it was once the instructions are deallocated). I must admit, I am surprised how much the instructions pages use up! But I am so glad it returns to a reasonable level when deallocated. I have now used the same code for the larger images in the game itself too, releasing the arrays etc after I use the UIImage imageNamed command to seperate the UIImageView's from the array first. It works like a charm, and I have no more memory issues! YAY!! I just want to thank everyone who helped me solve the problem. Very much appreciated. Sometimes I wonder if it was worth me buying these books, when I have got more help from other devs online! [EDIT] final code is now on my next post below (post 15). There was a slight adjustment to be made.
awesome. One thing, why do you have that [InstName retain] there, along with the second [InstName release] ? it seems unnecessary to me...
Yeah that's something I have already sorted out. Noticed it myself when I posted the pic and thought the same thing. Attached is the (amended) final code.