-1

This is related to a question i posted earlier.I am still stuck on it.Heres a description.I am creating a quiz app.It has a toolbar whose buttons are to be created dynamicaly each time the user clicks a button.I did it using a method which adds three buttons into an arrray, then uses a for loop to check the number of choices the question has and then create and add a button to the array for each choice.Later i use
[toolbar setitems:tempArray];

to add the buttons


But while doing this i am running into memory leaks.The app crashes after 200 questions.I found using instruments that the leaks were in button creation area.But after doing many experiments im at a loss about what to do.

I also have another question

Is there a way to find out the retain count of objects created by built in methods in iphone sdk.Specificaly,

1)Does NSMutableArray's addobject method increase the retain count of the added object 2)Is [[toolbar items] release] likely to cause trouble if i am intending to release the customBarButtonItem objects stored in it?

because wile playing with these options , the app either crashes immediately or the changes have no effect on the reported leaks

heres the code.Its got a lot of comment lines which are options i tried
- (void)CreateButtons{

      UIToolbar *tempToolBar=[[UIToolbar alloc] ]
      numberOfChoices=0;//set number of choice buttons at present to 0
      NSMutableArray *tempItems=[[NSMutableArray alloc] init];//Array for holding the buttons
      Question *question=[currentQuestion question];
      NSString *answer=[question answerOptions];
int numericAnswer=0;
numericAnswer=[answer characterAtIndex:0];  
//see if its a number or a character
if (numericAnswer > 96) { // its a character
    int choice;
    for (choice=97; choice <=numericAnswer ; choice ++) {

        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        [button setBackgroundImage:[UIImage imageNamed:@"gembtnblu.png"] forState:UIControlStateNormal];
        button.frame = CGRectMake(0, 0, TOOLBAR_BUTTON_WIDTH , TOOLBAR_BUTTON_HEIGHT);
        [button setTitle:[NSString stringWithFormat:@"%c",(char)choice] forState:UIControlStateNormal];
        [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
        [button addTarget:self action:@selector(ChoiceButtonTouched:) forControlEvents:UIControlEventTouchUpInside];
        [button setTag:choice];
        UIBarButtonItem *customBarItem = [[UIBarButtonItem alloc] initWithCustomView:button];

        if (isReviewing == TRUE) {
            customBarItem.customView.userInteractionEnabled=FALSE;
        }
        //Add button to the array
        [tempItems addObject:customBarItem];
        //release buttons
        [customBarItem release];
        numberOfChoices++;
    }
}
else {

    int choice;
    for (choice=49; choice<=numericAnswer; choice ++) {

        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        [button setBackgroundImage:[UIImage imageNamed:@"gembtnblu.png"] forState:UIControlStateNormal];
        button.frame = CGRectMake(0, 0, TOOLBAR_BUTTON_WIDTH , TOOLBAR_BUTTON_HEIGHT);
        [button setTitle:[NSString stringWithFormat:@"%c",choice] forState:UIControlStateNormal];
        [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
        [button addTarget:self action:@selector(ChoiceButtonTouched:) forControlEvents:UIControlEventTouchUpInside];
        [button setTag:choice];
        UIBarButtonItem *customBarItem = [[UIBarButtonItem alloc] initWithCustomView:button];

        //Add button to the array
        [tempItems addObject:customBarItem];

        if (isReviewing == TRUE) {
            customBarItem.customView.userInteractionEnabled=FALSE;
        }
        //release buttons
        [customBarItem release];

        numberOfChoices++;
    }
}

//load the image

UIButton *previousButton = [UIButton buttonWithType:UIButtonTypeCustom];
[previousButton setBackgroundImage:[UIImage imageNamed:@"prev.png"] forState:UIControlStateNormal];
[previousButton addTarget:self action:@selector(PreviousClicked:) forControlEvents:UIControlEventTouchUpInside];
previousButton.frame = CGRectMake(0, 0, TOOLBAR_BUTTON_WIDTH , TOOLBAR_BUTTON_HEIGHT);
UIBarButtonItem *customBarItem6 = [[UIBarButtonItem alloc] initWithCustomView:previousButton];
//[previousButton release];
self.prevButton=customBarItem6;

UIButton *nextButton= [UIButton buttonWithType:UIButtonTypeCustom];
[nextButton setBackgroundImage:[UIImage imageNamed:@"nex.png"] forState:UIControlStateNormal];
[nextButton addTarget:self action:@selector(nextClicked:) forControlEvents:UIControlEventTouchUpInside];
nextButton.frame = CGRectMake(0, 0, TOOLBAR_BUTTON_WIDTH, TOOLBAR_BUTTON_HEIGHT);
UIBarButtonItem *customBarItem7 = [[UIBarButtonItem alloc] initWithCustomView:nextButton];
//[nextButton release];
//Use this to put space in between your toolbox buttons
UIBarButtonItem *flexItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];

[tempItems addObject:flexItem];
[tempItems addObject:customBarItem6];
[tempItems addObject:customBarItem7];

//release buttons
[customBarItem6 release];
[customBarItem7 release];
[flexItem release];

//NSArray *items=[[NSArray alloc] initWithArray:(NSArray *)tempItems];
//[tempItems release];

//add array of buttons to toolbar
//if([[toolbar items] count]>0)

// { // [[toolbar items] release]; // } [toolbar setItems:tempItems animated:YES]; //[items release]; //[self.view addSubview:toolbar]; if(isReviewing == FALSE && isPractice == FALSE) {

    prevButton.enabled=FALSE;
}
//[toolbar bringSubviewToFront:customBarItem6.customView];

}

toolbar is created via ib

Yeah its a lot of code but it just creates buttons based on number of choices for a question.The two for loops are similar exept one puts a,b,c,d on the buttons while the other one puts 1,2,3,4.....In addition three buttons are created.One for next, previous and a flex item .This method is is called each time the user clicks teh next button.

humblePilgrim
  • 1,818
  • 4
  • 25
  • 47

2 Answers2

1

I can see a few things which are not very efficient memory-wise:

  1. You use lots of convenience initializers: buttonWithType and 'imageNamed`. These will autorelease themselves at some point in the future but not within your method.
  2. The item tempToolbar is allocated but never released. This will leak.
  3. Your mutable array tempItems also does not appear to be released: this will kill you completely since all your buttons are added to it...

Based on this I would suggest:

  1. Use of alloc/init methods instead of convenience constructors
  2. Alternatively: create an NSAutoReleasePool at the start of your method and drain it at the end: this will release all autoreleased entities.

Good luck

MiKL
  • 1,850
  • 1
  • 15
  • 23
  • I made tempArray as a class variable.Now instruments doesnot show anyleaks.Hope everything goes ok – humblePilgrim Mar 16 '11 at 13:13
  • @mithun. Do you empty it between calls or do you keep adding objects to it never releasing it. It does not matter whether its a class member or not. What matters is that all objects to add to it are retained by the array. Unless you release all items in the array or release the array itself, you are never releasing the memory held by these objects. – MiKL Mar 16 '11 at 13:20
  • I use removeAllObjects method on each call after checking its count for 0 – humblePilgrim Mar 16 '11 at 13:23
  • @mithun. This should work for this one. How about the other item `tempToolbar`? You should also have a look at your memory footprint while calling the method. Is the memory usage growing? Last regarding leak detection how often are you sampling for leaks? And one last thing: how big are the images you use for your buttons? – MiKL Mar 16 '11 at 13:36
  • the images are 4KB.Im sampling every 10 seconds.The momory usage is not growing as per my understanding.There are no leaks.And the allocations graph declines to zero after each upsurge.Hope its all fine – humblePilgrim Mar 16 '11 at 14:19
  • @mithun. I wish you all the best. And thanks for the approval. – MiKL Mar 16 '11 at 15:02
0

Difficult to follow all that code, but an easy part-answer to 1) is that, yes, [NSMutableArray addObject:] increase retain +1.

Erik Tjernlund
  • 1,963
  • 13
  • 12
  • Yeah its a lot of code but it just creates buttons based on number of choices for a question.The two for loops are similar exept one puts a,b,c,d on the buttons while the other one puts 1,2,3,4.....In addition three buttons are created.One for next, previous and a flex item .This method is is called each time the user clicks teh next button. – humblePilgrim Mar 16 '11 at 12:34