重用 UITableViewCell 与 KVO

reused UITableViewCell with KVO

重用 UITableViewCell 的表格视图,每个单元格都有自己的标签。这个Label是我定义的,UILabel的subclass。标签显示一个字符串。字符串的更改取决于 NSMutableDictionary。在标签 class 中,我正在使用 KVO 来添加观察者。当 NSMutableDictionary 中 key 的值发生变化时,标签会接收到这个变化并改变显示值。问题是当 NSMutableDictionary removeAllObjects 时。大多数单元格中的标签显示为“-.-”,没错。但是只有少数单元格的标签显示以前的值,这是不对的。好像是因为重用了tableviewcells,才出现这个bug。

Tableview Class:

//Add Observer

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{
// Add Observer
   NSDictionary* dic = [_paramters objectAtIndex:indexPath.row];
   if (!dic || dic.count <= 0) {
     return;
   }

  NSString* key = [dic.allKeys objectAtIndex:0];
  if (!key || key.length <= 0) {
    return;
  }

   ParameterTableViewCell* paramCell = (ParameterTableViewCell*)cell;
   //Add Observer
   paramCell.valueLabel.paramKey = key;
}

// Remove Observer
- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{

  ParameterTableViewCell* paramCell = (ParameterTableViewCell*)cell;
  //Remove Observer
  [paramCell.valueLabel removeKeyObserver:paramCell.valueLabel.paramKey];
}

Label Class
- (void)setParamKey:(NSString *)paramKey{
  if (![_paramKey isEqualToString:paramKey]) {
    [[CnogaCurveManager sharedCurveManager] addParameterValueObserver:self forParameterKey:paramKey];
    _paramKey = paramKey;
  }
}

- (void)removeKeyObserver:(NSString*)paramKey{
 [[CnogaCurveManager sharedCurveManager] removeParameterValueObserver:self forParameterKey:paramKey];
}

- (void)dealloc{
 [[CnogaCurveManager sharedCurveManager] removeParameterValueObserver:self forParameterKey:_paramKey];
}


//This is where I change label's value
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
                    change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
if([_paramKey isEqualToString:keyPath]){
    dispatch_async(dispatch_get_main_queue(), ^(){
        self.text = [[CnogaCurveManager sharedCurveManager] paramterValueForKey:keyPath];
        if (!self.text){
            self.text = @"-.-";
        }
    });
 }
}

CnogaCurveManager Class

- (void)addParameterValueObserver:(NSObject*)observer forParameterKey:(NSString*)parameterKey{
try {
    if(![NSString stringIsEmpty:parameterKey]){
        if ([self.obeseverKeys containsObject:parameterKey]) {
            return;
        }

        [self.parameterMeasurement addObserver:observer forKeyPath:parameterKey options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
        [self.obeseverKeys addObject:parameterKey];
       }
} catch (NSException *exception) {

}

}

- (void)removeParameterValueObserver:(NSObject*)observer forParameterKey:(NSString*)parameterKey{
try {
    if(![NSString stringIsEmpty:parameterKey]){
        if (![self.obeseverKeys containsObject:parameterKey]) {
            return;
        }

        [self.parameterMeasurement removeObserver:observer forKeyPath:parameterKey];
        [self.obeseverKeys removeObject:parameterKey];
    }
} catch (NSException *exception) {

}

}

你说问题来自重复使用的电池是对的。

当您在 dic 上调用 removeAllObjects 时,key 将是 nil 并且它在设置 [=16 之前生成 tableView:willDisplayCell: returns =] 再次。这就是为什么您会看到一些单元格显示以前的值。

要修复它,请在使用 prepareForReuse 方法重复使用单元格时重置 valueLabel.paramKey。将下面的代码放入 ParameterTableViewCell class

- (void)prepareForReuse {
    [super prepareForReuse];
    self.valueLabel.paramKey = @"";
}