views:

54

answers:

2

Hello all -

I am learning Obj-C but still occasionally have a difficult time wrapping my head around some of the mem management stuff. I am using custom cells with a UITableView, and implemented the cellForRowAtIndexPath method where I accidentally released the cell at the end. This obviously caused problems as the cell was also getting released when the tableView was popped. This led to a crash due to releasing the cell twice - no prob, understand.

However, as I kept working, I intermingled standard and custom cells, so my method got a bit more complex. My first try was the below, which caused the same problem as the above scenario. This is where I am a bit confused - since I am not releasing "cell", why can't I release "customCell" after I set cell to its value?

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

     UITableViewCell *cell;

     //CATEGORY_SECTION is a constant defined elsewhere
     if (indexPath.section == CATEGORY_SECTION) {
          cell = [tableView dequeueReusableCellWithIdentifier:@"StandardCellIdentifier"];
          if (cell == nil) {
               cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"StandardCellIdentifier"] autorelease];
               cell.accessoryType = UITableViewCellAccessoryCheckmark;
          }
          cell.labelText.text = myModelObject.name;

     } else {

          cell = [tableView dequeueReusableCellWithIdentifier:@"CustomCellIdentifier"];
          MyCustomCellClass *customCell;
          if (cell == nil) {
               UIViewController *helperController = [[UIViewController alloc] initWithNibName:@"MyCustomCell" bundle:nil];
               customCell = (MyCustomCellClass *)[helperController view];


               [helperController release];
          }

     customCell.myCustomLabel.text = myModelObject.description;
     cell = customCell;
     [customCell release];
     }

     return cell;
}

I understand that when I set cell = customCell, I am assigning customCell's memory address, not the actual object, to cell...so when I release customCell it is also in effect releasing cell? How would I actually copy customCell so I could release it? Or do I not have to release it (even though I alloc'd it) - it seems like a memory leak waiting to happen, how would you approach it?

For the record, here is the revised code I used to avoid this issue. This question isn't so much as finding a solution (since I have, below) but understanding what is happening behind the scenes. Thanks for any guidance!

My working method:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

     //CATEGORY_SECTION is a constant defined elsewhere
     if (indexPath.section == CATEGORY_SECTION) {
          UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"StandardCellIdentifier"];
          if (cell == nil) {
               cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"StandardCellIdentifier"] autorelease];
               cell.accessoryType = UITableViewCellAccessoryCheckmark;
          }
          cell.labelText.text = myModelObject.name;

          return cell;

     } else {

          MyCustomCell *customCell = (MyCustomCell *)[tableView dequeueReusableCellWithIdentifier:@"CustomCellIdentifier"];

          if (customCell == nil) {
               UIViewController *helperController = [[UIViewController alloc] initWithNibName:@"MyCustomCell" bundle:nil];
               customCell = (MyCustomCell *)[helperController view];
               [helperController release];
          }

          customCell.myCustomLabel.text = myModelObject.description;

          return customCell;
     }
}
+2  A: 

Right, you're releasing the same memory, which both variables point to. If you were setting a class property, for example, the property would probably be marked with retain. If a property has retain it means it wants to "own" the object. You could then release it.

In your case, your cell variable doesn't own the memory, so you can't release it.

Sean Clark Hess
So, assuming I had declared: UITableViewCell *cell; along with @property (nonatomic, retain) UITableViewCell *cell; in my .h file, it would work, since cell now had a retain, "owning" the memory, allowing customCell to be released with no consequence? That makes sense, if I am interpreting it correctly...
Jim
A: 

Please read the Apple memory management rules. In your first example either

a) customCell is an ivar

or

b) you made a mistake in transcribing the code and customCell is obtained from [helperController view].

Either way, you did not obtain customCell using new, alloc or a method containing "Copy". Nor did you retain customCell. Therefore, you must not release it (in the scope of your method).

JeremyP
OK, it makes sense that I didn't use new, alloc, copy, or retain. But when you say customCell must be a) an ivar or b) obtained from the viewcontroller, can you elaborate? It is not declared in the class, just in the method with MyCustomCellClass *customCell = (MyCustomCellClass *)[helperController view]; -- think I'm just confused by how you phrased your response. Thanks
Jim
In your first example, customCell was obtained from helperController: `customCell = (MyCustomCellClass *)[helperController view];` which is what I meant to by the "view controller".
JeremyP