-2

In my TableViewController I use custom cell, this cell has a scrollView. My cellForRowAtIndexPath method looks like:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:@"cell"];

    if (!cell) {
        cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cell"];

        // iOS 7 separator
        if ([cell respondsToSelector:@selector(setSeparatorInset:)]) {
            cell.separatorInset = UIEdgeInsetsZero;
        }

    }

    UIView *subview = [cell viewWithTag:indexPath.row + 1];
    if (!subview) {
       //... Set up the new cell
        [self addScrollViewForCell:cell andCellIndx:indexPath.row];
    }
    else {
       // ... Reuse the cell
    }

    return cell;
}

If view already exist - I'm trying do not add scrollView. If not - add. addScrollViewForCell: method:

- (void)addScrollViewForCell: (CustomCell *)tCell andCellIndx:(NSInteger)cIndx {

    UIScrollView * myScrollView = [[UIScrollView alloc]initWithFrame:CGRectMake(5, 62, 350, 61)];
    myScrollView.accessibilityActivationPoint = CGPointMake(100, 100);

    //Some settings
    // ...

    UILabel *lblH = [[UILabel alloc] init];
    lblH.textAlignment = NSTextAlignmentCenter;
    lblH.text = strWeekIdntfr;
    lblH.textColor = [UIColor blueColor];
    lblH.frame = CGRectMake(offsetScores, 0, cCurrWeekBallsWidth, 15);

    [myScrollView addSubview:lblH];

     myScrollView.tag = cIndx + 1;
     [tCell addSubview:myScrollView];
}

The problem is - when I scroll table to the bottom or to the up, scrollView begin to be added. Checking view by tag I try to differentiate reusable and new one cells, but this didn't work. How Can I solve this?

daleijn
  • 718
  • 13
  • 22
  • As of iOS 6, you don't need to check whether the `cell` is `nil` or not. Use `dequeueReusableCellWithIdentifier:forIndexPath:` will guarantee that an instance of `UITableViewCell` will always be returned. – yusuke024 Feb 11 '15 at 17:35
  • Why isn't the scroll view just a part of the custom cell? I think the best design is to have all the subviews in the custom cell, then just customize the view. That's the whole purpose of dequeuing reusable cells. – AdamPro13 Feb 11 '15 at 17:42
  • @SikhapolSaijit Yes, that's true, but only if you use cell prototypes or register a cell class/nib with that reuse identifier. – Rob Feb 11 '15 at 17:44
  • @Rob But you already have a subclass. Just add `[self.tableView registerClass:[CustomCell class] forReuseIndentifier:@"cell"]` in `viewDidLoad:` and do as @AdamPro13 said will save you a lot of headache. – yusuke024 Feb 11 '15 at 17:58
  • @sikhapol Agreed. Obviously, if you use cell prototype, you don't even need to do that. My point was simply that you need either cell prototype or manually register class (or NIB) with the reuse identifier if you want the `dequeue...` method to automatically instantiate it for you. – Rob Feb 11 '15 at 18:30
  • 1
    @Rob I'm sorry, I didn't look at OP's name and thought you were the OP :p – yusuke024 Feb 11 '15 at 18:33

2 Answers2

3

The reason is because an instance of UITableViewCell is reused when you scroll.

Each time it's being reused, this line UIView *subview = [cell viewWithTag:indexPath.row + 1]; will query for view with different tag. Say, you have 100 cells in this UITableView, a cell might be asked for tag 1, 6, 11, 16, 21 ... 96, which clearly it doesn't have. So it's likely to create a new view every time it's being reused. Multiply this with every cell in the pool and you will get hell load of new scroll views added to them.

To solve this: Just use a fix tag number.

So the line.

UIView *subview = [cell viewWithTag:indexPath.row + 1];

become:

UIView *subview = [cell viewWithTag:1];

And:

myScrollView.tag = cIndx + 1;

become:

myScrollView.tag = 1;

And as @AdamPro13 pointed out, a better and much more elegant way is that you create the scroll view as part of your custom cell. Just put it in initWithFrame:style: of the UITableViewCell's subclass.

yusuke024
  • 2,189
  • 19
  • 12
  • Yeah, I was going to remark that `[cell viewWithTag:indexPath.row + 1]` was at the very least silly, since the "name space" for tags is only the containing view. – Hot Licks Feb 11 '15 at 18:06
  • They stopped to be added but sometimes for different rows I see incorrect scrollView. – daleijn Feb 11 '15 at 18:20
  • @daleijn You have to move the code that you use to configure the scroll view to be after `if (!subview) { ... } else { ... }` because you have to configure it every time it's whether it's just been created or reused. – yusuke024 Feb 11 '15 at 18:27
  • @sikhapol but if I do that - they again will be added, isn't they? – daleijn Feb 11 '15 at 18:38
  • Just put the code you use to configure the scroll view there (like setting `text` for the label). The code that create a new scroll view can be left in `addScrollViewForCell:andCellIndx:`. – yusuke024 Feb 11 '15 at 18:42
  • @sikhapol in my case creating new or configure scrollView - the same. I have to add on scrollView some labels (this data represent rating marks by weeks, they can be various: on 1 week - 1 mark, on second - 2, on 5 - six, and this the reason why I decide to use scrollViews. I created in IB on my customCell scrollView, now I not addSubview, but work directly with cell.scrollView – daleijn Feb 11 '15 at 18:56
0

The best way that I found it just clear all subview from scrollView. For example like that:

[myCell.scrollView.subviewsmakeObjectsPerformSelector:@selector(removeFromSuperview)];
daleijn
  • 718
  • 13
  • 22