0

I am in the process of learning objective-C in my own time and creating my first iPhone application however I seem to be having problems releasing the memory of my allocated views. I think there is to much code to include in the question itself so I have created a small sample application and uploaded the code to github (here: https://github.com/MatthewStacey/PauseTest).

In the sample app I have three views, a main page, a game page and a pause view.

On the Main page there is a button which will take you to the game page (with fade in/out animation).

On the game page there is a button which will display the pause view (UIView).

On the pause view there are two buttons, one which will hide the view and leave the game page being displayed and another which will display the main menu.

Functionality wise the sample app does what it is supposed to do (i.e. there are no leaks and the appropriate views are displayed), however when I look at the app in Instruments Activity Monitor the memory being used continually increases as you show/hide the three different views.

I have spent the best part of two weeks reading and trying to figure out what I am not releasing correctly to no avail. Could someone please take a look at the project I have uploaded to github and tell me where I am going wrong and how I can overcome this problem?

I am happy to provide more information/clarification if it is needed. Please note I have targeted iOS4.

MattStacey
  • 875
  • 4
  • 12
  • 23

1 Answers1

1

You are leaking PauseViews.

In your GAME.m file, in the pausePressed method, you create a new instance of your PauseView class. When you add that as a subview to something, it gets retained by the superview. After the pausePressed method returns, you no longer have a reference to the PauseView and therefore cannot release it. On a related note, in your PauseView class' dealloc method, you have "[self removeFromSuperview]". This does not make sense, because if it had a superview at that point, it would have a retainCount of at least one, but then dealloc would never have been called in the first place. Put a breakpoint in the dealloc method of PauseView, and you'll see that it never gets called.

I used this method to find it: http://useyourloaf.com/blog/2011/3/8/using-heapshots-to-find-abandoned-memory.html

Create an ivar for your PauseView, and try this for your pausePressed method:

- (IBAction) pausePressed
{
    CGRect startFrame = CGRectMake(0, -500, 320, 480);
    if (!pv) {
        pv = [[PauseView alloc] initWithFrame: startFrame :10 :3];
        [pv setDelegate: self];
        [self.view addSubview:pv];
    }
    pv.frame = startFrame;
    [pv showPauseView];
}

And don't forget to release the ivar in dealloc.

bdmontz
  • 581
  • 6
  • 9
  • hi bdmontz, thanks for your response and the link it'll be very useful for me. I understand where the abandoned memory is being introduced now but I'm not 100% clear on how to fix it, are you suggesting I create a property for the PauseView in GAME.h and then try to release it in the pauseMenuResult method? Would I need to retain the PauseView or just use assign? If you could update your answer with your suggestion on how to fix it then I'll test and mark as the answer assuming it works. Thanks again for your help. – MattStacey Dec 05 '11 at 12:31
  • I would also suggest not using unnamed parameters in methods. You could change this: `- (id)initWithFrame:(CGRect)frame :(int) totalQuestions: (int) questionNumber` to this: `- (id)initWithFrame:(CGRect)frame totalQuestions:(int) totalQuestions questionNumber: (int) questionNumber` – bdmontz Dec 05 '11 at 19:38
  • hi bdmontz, thanks for your update and for the suggestion for the initWithFrame method I didn't know you could do that. Re the question, I have made the change suggested above but now when I click on the game button on the main view the app now crashes and says 'Program received signal: "EXC_BAD_ACCESS"' - thanks for persevering with me here? I have uploaded my second attempt to github at the above location if you can help to see? Feel free to change the code if it is easier - thanks again! – MattStacey Dec 06 '11 at 00:23
  • In the displayMainMenu method of your PauseTestAppDelegate, change the end from this: `if(self.gameViewController) { [self.gameViewController release]; // self.gameViewController = nil; }` to this: `self.gameViewController = nil;` Setting a property to nil will also release it. Your code was releasing the gameViewController but keeping the reference to it, so when you try to message it, you get a crash. Also, take a look at this question (http://stackoverflow.com/questions/5386160/how-to-enable-nszombie-in-xcode) to see how to enable zombies. – bdmontz Dec 06 '11 at 03:05
  • thanks a lot bdmontz - I feel like I have learnt a lot form your comments/advice! – MattStacey Dec 06 '11 at 19:12