1

I have UITableView, with CustomCell. In CustomCell there is UICollectionView with CustomUICollectionViewCell. Everything is created in the way, according to UICollectionView inside CustomTableCell. Then, let's say I have 12 rows. On the beginning I can see 6 of them. In CustomUICollectionViewCell, labels are fine, but when I scroll down, to see other cells, CustomUICollectionViewCells labels are not as expected. They are the same as first 6 rows, which are now scrolled up.

Where should I refresh CustomUICollectionViewCells label after scroll?

Example view: Before scrolling: enter image description here

After scrolling: enter image description here

However when debugging, when assigning data to cell, everything is assigned fine. All code is in the link as it's also my question. Seems that it's duplicating rows. I guess that it should be reloaded(?).

Added prepareForReuse method, as advised, but didn't help. Now my CustomCellClass looks:

@implementation TemperatureTableViewCell

    NSNumberFormatter *decimalStyleFormatter;

- (void)awakeFromNib
{
    [super awakeFromNib];
    UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];

    [flowLayout setItemSize:CGSizeMake(50, 50)];
    [flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
    self.collectionView = [[CollectionView alloc] initWithFrame: CGRectZero collectionViewLayout:flowLayout];
    [self.collectionView registerClass:[TemperatureItemCollectionViewCell class] forCellWithReuseIdentifier:@"TemperatureItemCollectionCell"];
    self.collectionView.showsHorizontalScrollIndicator = NO;
    self.collectionView.dataSource = self;
    self.collectionView.delegate = self;

    [self.contentView addSubview:self.collectionView];

}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    return self.collection.count;
}

-(void)collectionView:(CollectionView *)collectionView willDisplayCell:(TemperatureItemCollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
    TemperatureSensor *temp = self.collection[indexPath.item];
    cell.temperatureValue = temp.temperature.stringValue;
    cell.tempValTempCollViewCell.text = [NSString stringWithFormat:@"%@°C", cell.temperatureValue];
    cell.sensorName.text = temp.sensorName;
    cell.imageTempCollViewCell.image = [TemperatureImageHelper getTemperatureIcon:temp];
     [self.collectionView reloadData];
}

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    TemperatureItemCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"TemperatureItemCollectionCell" forIndexPath:indexPath];
    return cell;
}

- (void)setCollectionViewDelegate:(id)dataSourceDelegate indexPath:(NSIndexPath *)indexPath {
    self.collectionView.delegate = dataSourceDelegate;
}

@end

And my CustomCollectionViewCell:

@implementation TemperatureItemCollectionViewCell
-(void)awakeFromNib {
    [super awakeFromNib];

}
-(void)prepareForReuse {
    [super prepareForReuse];

    self.imageTempCollViewCell.image = nil;
    self.tempValTempCollViewCell.text = nil;
    self.sensorName.text = nil;
    self.temperatureValue = nil;

}
@end

My TableViewController

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if (_tempSensorsDictionary == nil)
        return 0;
    else {
        NSArray *allSensorKeys = [_tempSensorsDictionary allKeys];
        return [allSensorKeys count];
    }
}
-(void)tableView:(UITableView *)tableView willDisplayCell:(TemperatureTableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    [cell setCollectionViewDelegate:self indexPath:indexPath];    
}


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

    NSArray *nodeNumbers = [_tempSensorsDictionary allKeys];
    TemperatureTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath: indexPath];
    cell.collection = [_tempSensorsDictionary  objectForKey:nodeNumbers[indexPath.row]];
    //NSArray *nodeNumbers = [_tempSensorsDictionary allKeys];
    if([[UnitNameCache sharedUnitNameCache] getNameForId:nodeNumbers[indexPath.row]] != nil &&
       ![[[UnitNameCache sharedUnitNameCache] getNameForId:nodeNumbers[indexPath.row]] isEqualToString:@""]) {
        NSString *name = [NSString stringWithFormat:@"%@ (%@)", [[UnitNameCache sharedUnitNameCache] getNameForId:nodeNumbers[indexPath.row]], nodeNumbers[indexPath.row]];
        cell.unitNameLabel.text = name;
    } else {
        cell.unitNameLabel.text = nodeNumbers[indexPath.row];
    }
    return cell;
}

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return 85.0;
}
Micgal
  • 133
  • 1
  • 1
  • 11
  • Can you please share some screenshots or code? – Emre Önder Nov 16 '17 at 13:37
  • @EmreÖnder edited. Please see red one. From my api, there should be something different. – Micgal Nov 16 '17 at 13:44
  • use override func prepareForReuse() to nil all the params in your cell . https://stackoverflow.com/a/35957365/2000162 – TomCobo Nov 16 '17 at 13:56
  • @TomCobo can you please provide more details? Should I prepareForReuse collectionView to nil, in my CustomCell?? – Micgal Nov 16 '17 at 14:05
  • sure, not the cell. You need to override that method inside of the child cell. and nil all the labels or ui elements you have on it. – TomCobo Nov 17 '17 at 07:51
  • 2
    **Never** call `reloadData` in `willDisplayCell` – vadian Nov 17 '17 at 08:04
  • yes, never reloaddata inside of willDisplayCell or cellForItemAtIndexPath. otherwise you are reloading the entire collectionview for every cell that will be displayed. – TomCobo Nov 17 '17 at 08:12
  • Okay. Deleted reloadData, but still not help. BTW. To be sure, should I use reload data, only in external methods, e.g receiving data from somewhere? – Micgal Nov 17 '17 at 08:17
  • Seems to prepareForReuse is not being called. I have put there some NSLog, and it's not displaying.. – Micgal Nov 17 '17 at 08:35
  • @Micgal Can you please post the code from your `UITableViewController` that is handling the set up of all your `TemperatureTableViewCell` – Rhuari Glen Nov 17 '17 at 11:22
  • @RhuariGlen updated. – Micgal Nov 17 '17 at 11:24
  • @RhuariGlen seems that solved! – Micgal Nov 17 '17 at 11:25
  • @RhuariGlen I have prepareForReuse as you suggested, then moved content of willDisplayCell to cellForItemAtIndexPath in collectionView setup. and works as expected. – Micgal Nov 17 '17 at 11:26
  • @RhuariGlen however not sure why is this a difference. Do you have any idea? – Micgal Nov 17 '17 at 11:30
  • @Micgal Thats great! Glad you managed to sort it. Typically all setting up of cell code should be done within cellForRow or cellForItem as this is where you dequeue your cell from the tableView. Unsure of an exact reason, could be a timing issue. – Rhuari Glen Nov 17 '17 at 11:31

2 Answers2

3

Because UITableViewCells are reused for performance, caching can sometimes occur. In your TemperatureTableViewCell class you should override prepareForReuse and reset its properties. In your case you should clear the data you are populating it with. I would also keep prepareForReuse in TemperatureItemCollectionViewCell to avoid anymore issues.

- (void)prepareForReuse
{
  [super prepareForReuse];

  //Reset properties here.
  self.collection = nil;
  [self.collectionView reloadData];
}
Rhuari Glen
  • 497
  • 2
  • 5
  • I've added this method, but didn't help. Please see my updated question with code of my custom cell. – Micgal Nov 17 '17 at 07:14
  • @Micgal Try putting the `prepareForReuse` in your `TemperatureTableViewCell` class – Rhuari Glen Nov 17 '17 at 10:26
  • prepareForReuse is being called now. But not refreshing items. However prepareForReuse in TemperatureItemCollectionViewCell is not being called. – Micgal Nov 17 '17 at 10:45
  • @Micgal I have updated my answer again. Try reloading the collection view after clearing out your data. – Rhuari Glen Nov 17 '17 at 10:51
  • well, still the same. I am sure that collection si fine. As I've check it milion times. I have not any idea... – Micgal Nov 17 '17 at 11:00
0

I think this is what's happening. Inside of your child cell (I think it's collectionViewCell) you should reset all the values of the ui elements. Basically you are reusing one cell and you neeed to reset the values of the text or the images on it.

override func prepareForReuse() {
    super.prepareForReuse()
    titleLabel1.text = nil
    image1.image = nil
    ...
}
TomCobo
  • 2,886
  • 3
  • 25
  • 43
  • Well, updated question with collectionViewCell code. Seems that everything is set to nil in prepareForReuse. But still the same :/ – Micgal Nov 17 '17 at 08:02