6

Currently I'm using auto layout with storyboard to dynamically resize custom UITableViewCell's. Everything is working as it should except there is memory leak when scrolling.

I know the problem is from calling

[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];

from inside

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

My question is this, what would be the best way to create a reference cell? How to load a cell from storyboard without dequeueReusableCellWithIdentifier?

And is it ok to maybe call dequeueReusableCellWithIdentifier from viewDidLoad and create a reference cell as a property?

I need reference cell for sizing purposes.

Thanks for any help.

Farzad
  • 842
  • 2
  • 9
  • 26
Iki
  • 175
  • 1
  • 1
  • 6

3 Answers3

10

Regarding how to create reference cell (see original question), there are couple of options as I can see:

  1. create a custom cell with XIB, great article here -> a link!

    • this was pointed out to me by @smileyborg, thanks!
  2. create your custom cell in code, along with constraints.

  3. create your custom cell in storyboard as prototype cell

    • after that there are 2 options:
      • drag and drop custom cell from table view to the storyboard scene, as a top level nib object (not part of the view hierarchy), and simply create outlet to it.
      • copy custom cell and paste it to the storyboard scene. When using it this way, there is no need to register original cell with table for dequeue.
      • minor problem with both approaches is that once you drag and drop custom cell to the storyboard scene, you will not be able to see it visually and arrange UI.
    • great article here -> a link!

Thanks everyone for help!

Community
  • 1
  • 1
Iki
  • 175
  • 1
  • 1
  • 6
1

And is it ok to maybe call dequeueReusableCellWithIdentifier from viewDidLoad and create a reference cell as a property?

Yes, you can do this. Or lazy initialize the property:

- (UITableViewCell *)referenceCell
{
    if (!_referenceCell) {
        _referenceCell = [self.tableView dequeueReusableCellWithIdentifier:@"Cell"];
    }
    return _referenceCell;
}
Timothy Moose
  • 9,895
  • 3
  • 33
  • 44
  • It seems that this also will create leaks. I'm testing it right now. – Iki Apr 07 '14 at 07:52
  • Last night, I had an conversation with Tyler Fox (@smileyborg), he has created a great example for auto layout and dynamic table view height [link](http://stackoverflow.com/questions/18746929/using-auto-layout-in-uitableview-for-dynamic-cell-layouts-variable-row-heights/18746930#18746930), and he also confirmed that using dequeueReusableCellWithIdentifier outside of cellForRowAtIndexPath will probably create leaks. – Iki Apr 07 '14 at 07:57
  • Curious why @smileyborg thinks this will leak. My [TLIndexPathTools](https://github.com/wtmoose/TLIndexPathTools) uses this method to automatically calculate cell height nobody has ever reported a leak. And I just tested it. If you've got a scenario where it leaks, I'd like to take a look. – Timothy Moose Apr 07 '14 at 14:35
  • @TimothyMoose It's true that cells will leak when dequeued and not returned in cellForRowAtIndexPath. See discussion of this here: https://github.com/caoimghgin/TableViewCellWithAutoLayout/issues/16 Note that this probably isn't an issue if you're only calling it once and then storing the one cell for later use. But if you did this a number of times (or perhaps your view controller is created & destroyed frequently), you will see each of these cells hangs around with a retain count of 1 and thus is never deallocated. – smileyborg Apr 08 '14 at 05:28
  • @smileyborg Yep, I'm only dequeuing one per cell ID and reusing it. I keep them in a dictionary and they get dequeued properly along with the view controller. Since this is being done outside of the regular cell reuse cycle, I wouldn't expect them to be discarded from the reuse pool. Thanks for clarifying what you meant. – Timothy Moose Apr 08 '14 at 06:34
  • @smileyborg had a conversation with an apple engineer, he said that "That same method returns an autoreleased object, and in principle should not cause a memory leak." – Iki Apr 08 '14 at 07:00
  • @smileyborg but of course I agree with you about the leak, and it's very noticeable on my end because of frequent alloc/dealloc. It's probably a bug on their end. – Iki Apr 08 '14 at 07:24
0

You can just dequeue the cell once and store the height:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSNumber *height;

    if (!height) 
    {
        UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"YourCustomCell"];
        height = @(cell.bounds.size.height);
    }

    return [height floatValue];
}
Rafał Sroka
  • 39,540
  • 23
  • 113
  • 143