UITableView cell刚刚消失的回调?

7
我有一个UITableView,其中包含大量的图片内容。所以滚动不再流畅。 我想添加一个定时器来加载图片,当您滚动时,我为每一行创建一个定时器。如果单元格退出视图,我会取消定时器。否则,我会淡入图片。
我的问题是:是否有一个回调函数来处理单元格退出视图?我正在阅读文档,但我不确定是否有任何适用于我的需求。
感谢您的帮助!
编辑:我正在使用的代码(这是three20库,我正在使用自定义TTTableItemCell。“_tabBar1.tabItems = item.photos”是占用资源的代码行。在第一次加载时,它还好因为照片是异步从服务器加载的,但当我向后滚动或重新加载视图时,它们都被同步加载了,而且滚动对于iPhone 3G尤其不流畅。
- (void)setObject:(id)object {
    if (_item != object) {
        [super setObject:object];

        Mission* item = object;

        self.textLabel.text = item.name;
        _tabBar1.tabItems = nil;

        timerFeats = [NSTimer scheduledTimerWithTimeInterval:(0.5f) target:self selector:@selector(updateFeats) userInfo:nil repeats: NO];  
        //_tabBar1.tabItems = item.photos;
  }
}

-(void)updateFeats {
    DLog(@"timer ended");
    Mission* item = self.object;
    self._tabBar1.tabItems = item.photos;
}
4个回答

10

如果您使用 iOS 6 及以上版本,只需覆盖此方法:

- tableView:didEndDisplayingCell:forRowAtIndexPath:

当单元格已经离开视图,并且您可以获得它及其indexPath时,该方法将被调用。


4

好的,我找到了一种方法。

实际上有一个回调函数可以知道哪个单元格即将离开视图:

- (void)willMoveToSuperview:(UIView *)newSuperview;

所以我的代码是:
- (void)willMoveToSuperview:(UIView *)newSuperview {
    [super willMoveToSuperview:newSuperview];
    if(!newSuperview) {
        DLog(@"timer invalidated");
        if ([timerFeats isValid]) {
          [timerFeats invalidate];
        }

    }
}

如果没有新的Superview,该单元格将超出视图范围,所以我首先验证我的计时器尚未失效,然后取消它。


1
这似乎会在单元格进入视图时立即触发。 - Matt
1
@Matt 在 iOS 7.02 版本中,当你滚动一个单元格并将其滚回时,该方法可能根本不会被调用。但是,一旦它再次可见,prepareForReuse 方法就会被调用。在它不可见的时间里,只有 hidden 标志为 TRUE,但它仍然附加在 tableview 上。因此,没有 superview 的变化。 - Klaas

1
我建议使用KVO方法:
在您的awakeFromNib方法(或者您用来实例化单元格的任何方法)中添加以下内容:
- (void)awakeFromNib {
    [self addObserver:self forKeyPath:@"hidden" options:NSKeyValueObservingOptionNew context:nil];

    ...
}

请务必按照以下方式实现观察者的委托方法:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if([keyPath isEqualToString:@"hidden"]) {
        NSLog(@"cell is hidden");
    }
}

这对我没用。只有在单元格再次变为可见时,我才会收到通知。当系统将hidden设置为TRUE时,KVO不会被触发。我还尝试了覆盖setHidden:,但在转换为hidden = TRUE时也没有调用它。 - Klaas

0
当一个UITableView最初显示时,它会为每一行调用此方法。
- (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath

在这之后,每当需要一个新行时,该方法就会被调用,这通常是由于滚动以显示新行并将旧视图推出另一端而导致的。

因此,这是一个理想的钩子,可以找出哪些行是可见的。要检查哪些单元格是可见的,您可以调用

- (NSArray *)indexPathsForVisibleRows

因为TableView是在单元格被回收或新创建之前唯一持有对其的引用,所以您无法获取这些计时器的句柄。我的建议是创建一个NSMutableDictionary实例变量,并在创建单元格时将计时器添加到NSMutableDictionary中。
[timersForIndexs setObject:yourTimer forKey:indexPath];

现在当你收到 - (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath 时,你需要做一些像这样的事情

 NSMutableDictionary *tmpDictionary = [timersForIndexs copy];

 [tmpDictionary removeObjectsForKeys:[self.tableView indexPathsForVisibleRows]];

 NSArray *timers = [tmpDictionary allKeys];

 [timers makeObjectsPerformSelector:@selector(invalidate)];

我现在不在 Xcode 前面,所以这是干代码,请让我知道如果你有任何问题


我正在尝试这样做,但显然,如果我在一个不可见的单元格上使用[tableView cellForRowAtIndexPath:indexToRemove],我会得到一个null,所以我无法取消我的计时器。 - rnaud
我确实获得了可见行的数组,但问题是我只能通过方法cellForRowAtIndexPath访问这些行。任何其他行都会给我一个(null)。我猜这是因为单元格已被出列? - rnaud
那么我们能否看到正在消耗很长时间的代码,或许我们可以建议一些你可以做的事情。 - Paul.s
抱歉,我不了解three20框架,所以无法帮助你。 - Paul.s
好的,TTTableView只是UITableView的一个子类,所以你所有的方法都可以使用。我面临的唯一问题是,当单元格不在视图中时,我不知道如何访问已经运行的计时器。 - rnaud

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接