在`UItableViewCell`中加载`UIImage`不能按预期工作

时间:2015-03-14 13:40:50

标签: ios objective-c multithreading uitableview uiimage

到目前为止,我已经阅读了很多问题和答案[在这里或在网上],我无法找到问题的答案。

情况是:

我有一个包含UITableViewCell的自定义UIImageView, 我从服务器加载单元格的内容,这是按预期工作。 对于UIImageView我开始下载图像的新线程, 但图像没有显示UNTIL我在DataBase中下载了整个项目!

我已尝试在互联网上放置一个示例图像的链接,这有点好[有一些延迟]

问题:  1. UIImgeView未将其图像设置为“直到我加载整个表格”。  2. UIActivityIndicator在加载图像之前停止运行。

我认为我做错了导致这些问题。

这是我的代码:

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

OfferTableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"OfferCell"];
cellHeight = cell.frame.size.height;


Offer  * tmpOffer = _offersArray[indexPath.row];

[cell.likeButtonOutlet addTarget:self action:@selector(like:) forControlEvents:UIControlEventTouchUpInside];
[cell.disLikeButtonOutlet addTarget:self action:@selector(disLike:) forControlEvents:UIControlEventTouchUpInside];

//Offer Title
cell.offerTitle.text = tmpOffer.OfferTitle;

//Offer Image
[cell.offerImage setContentMode:UIViewContentModeScaleAspectFit];
cell.offerImage.image = [UIImage imageNamed:@"placeholder.png"];
if(!tmpOffer.imageLoaded){

    dispatch_async(dispatch_get_global_queue(0,0), ^{
        UIActivityIndicatorView * indicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
        [cell.offerImage addSubview:indicator];
        [indicator startAnimating];
        tmpOffer.OfferImageObject =  [[UIImage alloc]initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:tmpOffer.OfferImage]]];
        tmpOffer.imageLoaded = true;
        [indicator stopAnimating];
        [indicator removeFromSuperview];
        [cell.offerImage setImage:tmpOffer.OfferImageObject];
        cell.offerImage.clipsToBounds =YES;
        cell.offerImage.layer.cornerRadius = 5;
        tmpOffer.imageLoaded = true;
    });
}

//Refresh the table if it shows the last cell
if(indexPath.row == _offersArray.count-1){
    UILabel * updating = [[UILabel alloc]initWithFrame:CGRectMake(20, 20, 70, 30)];
    updating.text = @"جاري التحديت ...";
#warning show updating message

    [self refresh];

}
return cell;
}

,这是更新方法:

-(void)refresh{
NSMutableString * path = [NSMutableString stringWithString: @"api/Offers?$top=4&$skip="];
NSUInteger numOfElements = [_offersArray count];
NSString * strNumOfElements =[NSString stringWithFormat:@"%ld",(long)numOfElements];
[path appendString:strNumOfElements];
[[RKObjectManager sharedManager]getObjectsAtPath:path parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult)

 {
     int start = (int)_offersArray.count;



     if(mappingResult.array.count !=0){
         [_offersArray  addObjectsFromArray: [mappingResult.array mutableCopy]];
         NSMutableArray * indexesToBeReloaded = [[NSMutableArray alloc]init];
         for(int i =start   ; i<(int)_offersArray.count;i++){
             [indexesToBeReloaded addObject:[NSIndexPath indexPathForRow:i inSection:0]];
         }

         [self.tableView insertRowsAtIndexPaths:indexesToBeReloaded withRowAnimation:UITableViewRowAnimationNone];
         }
     else{
         UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"لا عروض جديدة الان " message: @"وصلت إلى ابق بالقرب لمتابعة أفضل العروض (:" delegate:nil cancelButtonTitle:nil otherButtonTitles: @"حسناً",nil];
         [alert show];
     }
 } failure:^(RKObjectRequestOperation *operation, NSError *error) {
     UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"Error" message:error.description delegate:nil cancelButtonTitle:@"Okay" otherButtonTitles: @"",nil];
     [alert show];
 }

 ];

}

非常感谢您的帮助..

2 个答案:

答案 0 :(得分:2)

所有与UI相关的工作都应该在主线程中完成。

您可能应该执行以下操作:

1)创建以URL为键,图像为值的图像字典。使用此功能可以在加载后保留图像副本,因此您只需执行一次。

2)不要在后台线程中进行任何UI更新。使活动指示器成为细胞的属性,以便细胞携带它。随着细胞的重复使用!你只需要创建一次。如果单元格图像位于字典中且活动不是nil,请确保将其删除并停止。如果需要加载图像,请根据需要创建活动并添加。在进行后台加载之前启动指示器。

3)在后台线程中,仅执行图像的加载。加载后,将调度同步到主线程,调用您添加的imageLoaded方法,该方法将图像作为参数,加载的单元格索引为索引。在此方法中,将图像添加到字典中并要求表重新加载indexPath处的行。这次单个单元格将停止指示器并显示图像,因为它将跟随2)。

这将确保您的单元格在图像到达时更新,并且所有UI操作都在主线程上发生。

您需要跟踪正在加载的图像,这样您才能进行多次运行。你在我当前的代码中已经考虑过这个问题,如果是这样的话,有人会在屏幕上滚动一个单元格并返回。

答案 1 :(得分:2)

在UITableViewCell中加载图像的最佳方法是AFNetworking UIImageView Category类。

AFNetworking库导入您的项目&amp; UIImageView+AFNetworking课程也是如此。

#import "AFHTTPRequestOperation.h"
#import "UIImageView+AFNetworking.h"

然后在cellForRowAtIndexPath内加载图片,如下所示。

__weak OfferTableViewCell *weakCell = cell;

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:strImageLink]];

        [weakCell.offerImage setImageWithURLRequest:request
                                      placeholderImage:nil
                                               success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
                                                   weakCell.offerImage.image = image;
                                                   [weakCell setNeedsLayout];
                                               } failure:nil];

这将为您异步完成所有事情