从运行中取消完成处理程序块

时间:2012-10-26 16:09:10

标签: objective-c objective-c-blocks nsoperation

我正在使用一个在后台运行的库,然后调用一个完成处理程序。一切都很标准。

[[LastFm sharedInstance] getInfoForArtist:@"Pink Floyd" successHandler:^(NSDictionary *result) {
    // Do stuff...
} failureHandler:nil];

我实际上是在tableview中使用它:在每个单元格(子类)中,我获得有关艺术家的信息并显示它。这也是问题:当单元格移出屏幕并重新用于另一位艺术家时,前一位艺术家的successHandler仍然可以执行,导致标签和图像快速连续多次变化。

我的想法是创建一个NSOperationQueue,在其中添加getInfoForArtist调用,并确保它可以被取消:

NSBlockOperation *operation = [[NSBlockOperation alloc] init];
__weak NSBlockOperation *weakOperation = operation;

[operation addExecutionBlock:^{
    [[LastFm sharedInstance] getInfoForArtist:mediaItem.artist successHandler:^(NSDictionary *result) {
        if (weakOperation.isCancelled) {
            return;
        }
        // Do stuff...
    } failureHandler:nil];
}];

[self.queue addOperation:operation];

问题是weakOperation在successHandler中始终为null。如果我将其更改为__block而不是__weak,则weakOperation是正确的实例,但其isCancelled状态始终为NO

我在正确的时间调用[self.queue cancelAllOperations];,此时单元格已移出屏幕。

所以我的问题是,在将该单元格重新用于另一位艺术家后,如何防止successHandler运行?

1 个答案:

答案 0 :(得分:2)

问题在于您正在调用异步API。操作的生命周期是对getInfoForArtist:successHandler:的调用,可能会立即返回。在执行异步回调时,操作已被处理掉,这就是回调块内引用为零的原因。

当successHandler执行时,取消操作没有意义 - 你不会节省网络资源,你也可以在本地保存查找结果。 UI问题是您不应直接引用单元格(或其子视图,如果您重复使用它们)。您可以考虑将结果存储在键入行的NSDictionary或艺术家ID的本地NSIndexPath中。然后,在cellForRowAtIndexPath:中,首先在进行LastFM调用之前检查该字典。在successHandler回调中,您可以遍历tableView的visibleCells并尝试从字典中加载数据。