0

I have a UITableViewCell subclass. I want to add a UIImageView as a subview, but make sure to do proper reuse so that I am not adding the subview over and over. I also want to make sure to nil out the image in prepareForReuse.

What is the proper method for doing this?

Nic Hubbard
  • 41,587
  • 63
  • 251
  • 412
  • Are you using prototype cells in a storyboard? – Paulw11 Jun 22 '16 at 06:05
  • @Paulw11 - No, these are custom drawn cells. – Nic Hubbard Jun 22 '16 at 06:06
  • 1
    Then you should add the imageview in `initWithStyle:resuseIdentifier`. You can nil the current image in `prepareForReuse` or in `cellForRowAtIndexPath` – Paulw11 Jun 22 '16 at 06:07
  • @Paulw11 - I am not using `initWithStyle:resuseIdentifier`. I am using `dequeueReusableCellWithIdentifier:forIndexPath:`. – Nic Hubbard Jun 22 '16 at 06:28
  • @NicHubbard why using viewWithTag is a bad practice. Why do apple introduced storyboard prototype cells then . – Muhammad Adnan Jun 22 '16 at 06:28
  • @MuhammadAdnan - Apple recommended a long time ago to stop doing this. – Nic Hubbard Jun 22 '16 at 06:29
  • `dequeueResuableCellWithIdentifier:forIndexPath` calls `initWithStyle:reuseIdentifier` when it needs to allocate a new cell. Refer to the UITableViewCell docs – Paulw11 Jun 22 '16 at 06:29
  • @Paulw11 - Mine is never getting called. Setting a breakpoint, it never stops there. So my subviews never get added. – Nic Hubbard Jun 22 '16 at 06:30
  • @NicHubbard but apple sample codes are still using ViewWithTag – Muhammad Adnan Jun 22 '16 at 06:33
  • @MuhammadAdnan - It was talked about at WWDC a few years back. They said transition away from it. – Nic Hubbard Jun 22 '16 at 06:34
  • @NicHubbard if your cellForRowAtIndexPath is written properly you shouldn't have any issues. You need to check if the dequeued cell is nil, if so then alloc init the cell and add the UIImageView instance to it. That way the cell then gets reused with all its subviews. If you post your cell cellForRowAtIndexPath that would be useful. – pnizzle Jun 22 '16 at 06:35
  • Can you show where you are dequeueing your cell and where you have registered your cell's class? I just ran a test and `initWithStyle:reuseIdentifier:` was called – Paulw11 Jun 22 '16 at 06:41
  • @Paulw11 - I hadn't registered the cell. Did so, and now it works. – Nic Hubbard Jun 22 '16 at 06:41
  • Great, I'll ad an answer – Paulw11 Jun 22 '16 at 06:41

4 Answers4

3

In your custom cell subclass you should add any required views in the initWithStyle:reuseIdentifier: method. As long as you have registered your cell class against the reuse identifier in your table view then this initialiser will be called by dequeueReusableCellWithIdentifier:forIndexPath: whenever a new cell is required. This method will not be called when a cell is reused, so your image view won't be added more than once.

You can clear the image view's current image in the cell class's prepareForReuse method.

Paulw11
  • 108,386
  • 14
  • 159
  • 186
0

Proper way to clean cell before reuse is

-(void)prepareForReuse;

just set self.imageView.image = nil;

And to create UIImageView , I'd do something like that:

- (instancetype)initWithFrame:(CGRect)frame {
   self = [super initWithFrame:frame];
    [self setup];
    return self;
}

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    [self setup];
    return self;
}

- (void)setup {
/// Create your UIImageView and set layout
}
Konstantin
  • 861
  • 4
  • 12
  • I guess I am also asking the location to add the `UIImageView` as a subview, so that it doesn't get added each time the cell is called. – Nic Hubbard Jun 22 '16 at 06:11
0

For proper reuse of cell, register cell xib in viewDidLoad in UIViewController class and then write

CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell_ID"];

and then load image in imageView inn cell.This guarantees reuse of cell.

Anirban iOS
  • 957
  • 7
  • 14
0

You need to add the UIImageView as a property of the UITableviewCell subclass. That way in cellForRowAtIndexPath you just say myCellInstance.profilePicView.image = ...

Have a look at my answer here on how I added textfields as cell subviews. Look specifically at the override for initWithStyle:reusableIdentifier: in the PersonCell class. No use of prototype cells in storyboard, no use of viewWithTag, just as you want.

Here is what the cellForRowAtIndexPath would look like if the Person class had a profile pic :

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    PersonCell *cell = nil;
    cell = [tableView dequeueReusableCellWithIdentifier: @"CellWithNameAndSurname"];
    if(!cell)
    {
        cell = [[PersonCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"CellWithNameAndSurname"];
        cell.contentView.backgroundColor = [[UIColor blueColor] colorWithAlphaComponent: 0.08f];
        cell.delegate = self;
    }

    //this should be outside the above if statement!
    Person *respectivePerson = _peopleArray[indexPath.row];
    cell.profilePicView.image = respectivePerson.profilePic;
    cell.nameTextField.text = respectivePerson.name;
    cell.surnameTextField.text = respectivePerson.surname;
    cell.positionLabel.text = [NSString stringWithFormat:@"%i", (int)indexPath.row];

    return cell;
}
Community
  • 1
  • 1
pnizzle
  • 6,243
  • 4
  • 52
  • 81