在UITableViewCell中异步加载图像

时间:2014-06-20 06:47:07

标签: ios objective-c uitableview asynchronous

我想刷新一个已经完成异步加载的单元格。

我知道有两种方法可以做到,但没有一种方法是我想要的。这就是我所知道的:

[myTableView reloadData];

或者

 [myTableView beginUpdates];
 [myTableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPathOfMyCell] withRowAnimation:UITableViewRowAnimationNone];
 [myTableView endUpdates];

直接从我的自定义UITableViewCell调用我的asynchrone方法来加载图像。这意味着它独立于我的UITableView。我的最终解决方案是将my UITableViewCell作为参数传递给当前单元格的索引。这看起来像是一个非常丑陋的解决方案。

有人知道另一种解决方案吗?

修改

[myCacheClass loadUIImageFromPath:photo.mediumDistURL];

loadUIImageFromPath:(NSString *) path{
  //Some code to load the image.
  if(![weakSelf.delegate respondsToSelector:@selector(MyCacheDidLoadImageFromCache:)])
    [weakSelf setDelegate:appDelegate.callbacksCollector];
  [weakSelf.delegate MyCacheDidLoadImageFromCache:image];
 }

MyCacheDidLoadImageFromCache的实施:

- (void) CacheCacheDidLoadImageFromCache: (UIImage *) image{
  DDLogInfo(@"Successfully load image from cache : %@", [image description]);
  myImageView.image = image;
}

5 个答案:

答案 0 :(得分:1)

已经为这种情况定义了许多更好的解决方案。您可以使用复杂的第三方代码AsyncImageViewAFNetworking

答案 1 :(得分:1)

您可以通过NSNotificationCenter进行间接。该表可以订阅通知:

[[NSNotificationCenter defaultCenter] addObserver:self
    selector:@selector(dataAvailableNotification:) 
    name:@"MyDataNowAvailable"
    object:nil];

当数据可用时,缓存将发布:

[[NSNotificationCenter defaultCenter] postNotificationName:@"MyDataNowAvailable" 
    object:self userInfo:@{@"Data": theData}];

然后该表通过将数据映射到适当的单元格并触发重绘来响应此通知:

- (void) dataAvailableNotification:(NSNotification *) notification
{
    DataObject *theData = notification.userInfo[@"Data"];
    // add code here to find which cell(s) this data is displayed in
    [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
    // etc
}

这种方法的好处是它可以推广到多个视图中显示相同数据的情况。

答案 2 :(得分:0)

您不需要传递UITableViewCell,而是通过NSIndexPath来获取该特定单元格。 &安培;然后使用reloadRowsAtIndexPaths方法重新加载。

要获取chache类文件中的表容器,请使用属性。

@property (nonatomic, assign) UITableView *tableView;

然后在实施中

loadUIImageFromPath:(NSString *) path forCell(NsIndexPath*)indexPath{
  //Some code to load the image.
  if(![weakSelf.delegate respondsToSelector:@selector(MyCacheDidLoadImageFromCache:)])
    [weakSelf setDelegate:appDelegate.callbacksCollector];
  [weakSelf.delegate MyCacheDidLoadImageFromCache:image forCell:indexPath];
 }

- (void) CacheCacheDidLoadImageFromCache: (UIImage *) image forCell(NSIndexPath*)indexPath{
  DDLogInfo(@"Successfully load image from cache : %@", [image description]);
  [tableView beginUpdates];
  [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
  [tableView endUpdates];
  myImageView.image = image;
  //tableView is from property & you have to pass NSIndexPath
}

&安培;在您的ViewController中将此属性指定为

myCacheClass.tableView = yourTableView;
[myCacheClass loadUIImageFromPath:photo.mediumDistURL forCell:indexPath];

答案 3 :(得分:0)

在设置子类TableViewCell之后将其放在- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 中。

        NSURL *imageURL = [NSURL URLWithString:@"your image url"];

        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
            NSData *imageData = [NSData dataWithContentsOfURL:imageURL];

            if (imageData) {
                UIImage *image = [UIImage imageWithData:imageData];

                if (image) {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        YourCellSubclass *updateCell = (id)[tableView cellForRowAtIndexPath:indexPath];

                        if (updateCell) {
                            updateCell.yourImageView.image = image;
                        }
                    });
                }
            }
        });

在此代码中,每个单元格在加载单元格时都会发出异步图像请求。如果数据返回,它会尝试从中创建UIImage。如果该图像有效,则仅在单元格仍然可见时才更新主线程上的图像。

每次加载单元格时,此代码都会对图像进行网络调用。您可能希望最有可能实现某种缓存。您要执行的缓存类型/数量取决于您的数据的动态程度。

答案 4 :(得分:0)

所以这是基于块的解决方案,无需将tableViewindexPath指针传递给单元格。我们将实现completionBlock。您应该熟悉这种方法:

<强> CustomCell.h:

// Define block as a typedef
typedef void (^CellCompletionHandler)(BOOL);
@interface MyTableViewCell : UITableViewCell

// Take a predefined block as a parameter
- (void)initWithImageURL:(NSURL *)URL completionHanlder:(CellCompletionHandler)completion;

@end

<强> CustomCell.m:

- (void)initWithImageURL:(NSURL *)URL completionHanlder:(CellCompletionHandler)completion
{
    // Take the URL and call cell's inner loading method
    // Pass the completion block to it
    [self doSomethingWithCellCompletionHandler:completion];
}

- (void)doSomethingWithCellCompletionHandler:(CellCompletionHandler)completion
{
    // When you finish loading your image from cache
    // call this to tell the block that you finished
    completion(YES);
}

<强>的cellForRowAtIndexPath:

[cell initWithImageURL:[NSURL URLWithString:@"your URL"]completionHanlder:^(BOOL finishedLoading) {
        if(finishedLoading)
        {
            // Here you can use indexPath to check whether it's visible
            // in order to reload it
            NSLog(@"Finished loading image");
        }

    }];