【问题标题】:UIImageViews in UITableViewCells are recreating themselves in cached cellsUITableViewCells 中的 UIImageViews 在缓存单元格中重新创建自己
【发布时间】:2013-02-16 03:43:11
【问题描述】:

我有一个UITableViewCell,我需要将插页式图片随机放入其中一些。这是有效的,但由于单元格的缓存,图像会在表格的下方重复出现。假设我已经预先决定将图像放在单元格 1、12 和 25 中,这些单元格将有它们的图像,但在单元格 1 之后,单元格 4、8 等也可能包含第一张图像。

我猜我需要做的是专门告诉cellForRowAtIndexPath 清除缓存并删除任何不符合添加图像标准的图像。我该怎么做呢?我已经在 if 语句上尝试了 else 来做出决定并分配图像。在那个else 中,我尝试将UIImageView 的图像设置为nil,但这并没有任何区别。

有没有其他方法可以清除缓存以防止这些图像定期在页面上发送垃圾邮件?这是我的cellForRowAtIndexPath 方法,当前在最后一个else 中的行对图像没有影响,因此(我认为)它们需要替换为有效的方法!

- (UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath
{
    // Make and allocate the cell if necessary.
    CustomCell *cell = [tableView dequeueReusableCellWithIdentifier: @"Cell"];
    if (cell == nil) {
        cell = [[CustomCell alloc] initWithStyle: UITableViewCellStyleValue1 reuseIdentifier: @"Cell"];
    }
    cell.lineLabel.text = [[self.fetchedResultsController objectAtIndexPath: indexPath] line];
    cell.actorLabel.text = [[self.fetchedResultsController objectAtIndexPath: indexPath] actor];
    [cell.lineLabel sizeToFitMultipleLines];

    // Get the size each label needs to be when constrained to set width and very long height (8000).
    CGSize labelSize = [cell.lineLabel.text sizeWithFont: cell.lineLabel.font constrainedToSize: CGSizeMake(265, 8000)];

    if ([[cellsToContainInterstitialImages allKeys] containsObject: [thisLine.lineID stringValue]]) {

        UIImageView *interstitialImage = [[UIImageView alloc] init];
        NSNumber *cellTypeNumber = [cellsToContainInterstitialImages valueForKey: [thisLine.lineID stringValue]];
        kInterstitialCellType cellType = [cellTypeNumber intValue];

        if (cellType == kInterstitialCellTypeFirst) {
            interstitialImage = [[UIImageView alloc] initWithImage: [UIImage imageNamed: @"man.png"]];
        }
        else if (cellType == kInterstitialCellTypeSecond) {
            interstitialImage = [[UIImageView alloc] initWithImage: [UIImage imageNamed: @"woman.png"]];
        }
        else {
            interstitialImage = [[UIImageView alloc] initWithImage: [UIImage imageNamed: @"child.png"]];
        }

        [interstitialImage setFrame: CGRectMake(10, cell.lineLabel.frame.size.height + cell.actorLabel.frame.size.height + 10, 150, 150)];
        [cell addSubview: interstitialImage];
    } else {
        UIImageView *interstitialImage = [[UIImageView alloc] init];
        [interstitialImage setImage: nil];
    }

    return cell;
}

【问题讨论】:

    标签: ios objective-c caching uitableview


    【解决方案1】:

    代码的else 分支不会将interstitialImage 图像添加到单元格中。您应该更改代码以在单元格的构造函数中添加UIImageView,这样您就必须在cellForRowAtIndexPath 中设置图像,而不是添加子视图。

    UIImageView 添加到您的CustomCell,将其设为私有,并提供一个属性供cellForRowAtIndexPath 使用:

    @interface CustomCell : UITableViewCell {
        UIImageView *_interstitialImage;
    }
    @property (nonatomic,readonly) UIImageView *interstitialImage;
    @end
    
    @implementation CustomCell 
    -(id)initWithStyle:(UITableViewCellStyle) style reuseIdentifier:(NSString*)reuseId {
        if (self = [super initWithStyle:style reuseIdentifier:reuseId]) {
            _interstitialImage = [[UIImageView alloc] init];
             [_interstitialImage setImage: nil];
             [_interstitialImage setFrame: CGRectMake(10, cell.lineLabel.frame.size.height + cell.actorLabel.frame.size.height + 10, 150, 150)];
             [cell addSubview: _interstitialImage];
        }
        return self;
    }
    -(UIImageView*)interstitialImage {
        return _interstitialImage;
    }
    @end
    

    现在您的cellForRowAtIndexPath 将使用cell.interstitialImage 而不是一直分配新的UIImageView。这样可以避免多次添加图像:

    if ([[cellsToContainInterstitialImages allKeys] containsObject: [thisLine.lineID stringValue]]) {
        NSNumber *cellTypeNumber = [cellsToContainInterstitialImages valueForKey: [thisLine.lineID stringValue]];
        kInterstitialCellType cellType = [cellTypeNumber intValue];
    
        if (cellType == kInterstitialCellTypeFirst) {
            [cell.interstitialImage setImage:[UIImage imageNamed: @"man.png"]];
        } else if (cellType == kInterstitialCellTypeSecond) {
            [cell.interstitialImage setImage:[UIImage imageNamed: @"woman.png"]];
        } else {
            [cell.interstitialImage setImage: [UIImage imageNamed: @"child.png"]];
        }
    } else {
        [cell.interstitialImage setImage: nil];
    }
    

    【讨论】:

    • 对不起,我不太明白。我的UIImageView 不是已经添加到构造函数中了吗?这是cellForRowAtIndexPath 之外的单独方法吗?你能稍微澄清一下答案吗?
    • 如果我尝试添加私有 @interface 部分,我会收到 Duplicate interface declaration 错误。知道为什么会这样吗?
    • @lukech 该示例展示了您在自定义单元格的实际声明中可以做什么(当然,保留您的其他方法)。如果您愿意,您也可以进行课程扩展,但这只是个人喜好问题。如果您想走扩展路线,请将@interface CustomCell : UITableViewCell 替换为@interface CustomCell ()
    • 不,else 分支并不总是被占用,问题肯定是 initWithStyle 没有被调用。这真的很令人困惑,因为我可以从字面上看到它在 cellForRowAtIndexPath 中被调用 :)
    • @lukech 是的,完全正确 - 这是正在发生的事情的答案:link
    【解决方案2】:

    最简单的解决方案应该是使用UITableViewDelegate 协议的– tableView:willDisplayCell:forRowAtIndexPath: 方法。用这种方法清洁你的细胞。

    【讨论】:

    • 但是我怎么知道我想将图像留在哪个单元格中,以及我想从哪个单元格中删除它呢?我不能只清理每个单元格,否则会从它们应该在的单元格中删除图像,不是吗?
    • 如果您知道您的图像应该在哪些单元格中,您可以使用 indexPath 参数来跟踪它们并清理需要的单元格。
    • 使用willDisplayCell... 比在cellForRow... 中正确获取图像更容易吗?
    • 我认为这个解决方案会奏效,但它会是一个权宜之计。将图像放入自定义类是正确的方法。
    • 通过在 willDisplayCell 中将单元格重置为适当/初始状态,您可以在 cellForRow 中获得更简单/系统的代码
    【解决方案3】:

    问题是在if 部分中添加了一个图像视图。这意味着随着单元格的重复使用,您会不断添加越来越多的图像视图。

    else 部分中,您创建一个虚拟图像视图并将其图像设置为nil。此代码不符合您的预期 - 清除任何现有图像。

    您需要做的是确保永远不会向单元格添加第二个图像视图。当您需要清除图像时,您会获得对现有图像视图的引用,而不是创建新的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-27
      • 2015-03-22
      相关资源
      最近更新 更多