使用 KVO 重用 UITableViewCell

Posted

技术标签:

【中文标题】使用 KVO 重用 UITableViewCell【英文标题】:reused UITableViewCell with KVO 【发布时间】:2019-01-31 10:40:06 【问题描述】:

重用 UITableViewCell 的 tableview,每个单元格都有自己的 Label。这个标签是我定义的,UILabel 的一个子类。标签显示一个字符串。并且字符串的更改取决于 NSMutableDictionary。在标签类中,我使用 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) 




【问题讨论】:

【参考方案1】:

您说问题来自重复使用的单元是对的。

当你在dic 上调用removeAllObjects 时,key 将是nil 并且它使tableView:willDisplayCell: 在再次设置paramCell.valueLabel.paramKey 之前返回。这就是为什么您会看到一些单元格显示以前的值。

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

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

【讨论】:

感谢您的热心回复,但这并不能解决我的问题。 可以添加tableView:cellForRowAtIndexPath:方法吗? 你有Skype账号吗?我可以和你签约吗?非常感谢

以上是关于使用 KVO 重用 UITableViewCell的主要内容,如果未能解决你的问题,请参考以下文章

UItableViewCell:移除观察者

如果文本为空,UITableViewCell detailTextLabel 不支持 KVO?苹果漏洞?

UITableViewCell 没有正确重用?

为啥手动重用的 UITableViewCell 在重新加载行时会消失?

UITableViewCell 重用时为空白

UITableViewCell的重用机制