在 `UItableViewCell` 中加载 `UIImage` 没有按预期工作
Loading `UIImage` inside `UItableViewCell` not working as expected
今天我已经[在这里或在网上]阅读了很多问题和答案,但我找不到问题的答案。
情况是:
我有一个包含 UIImageView
的自定义 UITableViewCell
,
我从服务器加载单元格的内容,这按预期工作。
对于 UIImageView
我开始了一个新线程来下载图像,
但直到我将整个项目下载到我的数据库中时,图像才显示出来!
我试过将 link 放到互联网上的示例图片中,效果还不错 [但有一些延迟]
问题:
1. UIImgeView
没有将其图像设置为直到我加载整个 table。
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];
}
];
}
非常感谢您的帮助..
所有UI相关工作都应该在主线程中完成。
您可能应该执行以下操作:
1) 创建一个图像字典,以 URL 为键,图像为值。使用它来保存加载后的图像副本,因此您只需执行一次。
2) 不要在后台线程中执行任何 UI 更新。使 activity 指示器成为单元格的 属性,以便单元格携带它。随着细胞得到重用!你只需要创建一次。如果单元格图像在字典中并且 activity 不为零,请确保将其删除并停止。如果需要加载图像,请根据需要创建 activity 并添加它。在执行后台加载之前启动指标。
3) 在后台线程中,只做图片的加载。加载后,向主线程同步调用您添加的 imageLoaded 方法,该方法将图像作为参数和加载所针对的单元格 indexPath。在此方法中,将图像添加到您的字典并要求 table 重新加载 indexPath 处的行。这次单个单元格将停止指示器并显示图像,因为它会跟随 2).
这将确保您的单元格在图像到达时更新,并且所有 UI 操作都发生在主线程上。
您需要跟踪哪些图像正在加载,这样您就不会有多个 运行。你已经有这个问题了我认为在你当前的代码中如果有人将一个单元格滚动到屏幕外并返回。
在 UITableViewCell 中加载图像的最佳方式是 AFNetworking UIImageView 类别 class。
将 AFNetworking
库导入您的项目 & UIImageView+AFNetworking
class。
#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];
这将为您异步完成所有事情
今天我已经[在这里或在网上]阅读了很多问题和答案,但我找不到问题的答案。
情况是:
我有一个包含 UIImageView
的自定义 UITableViewCell
,
我从服务器加载单元格的内容,这按预期工作。
对于 UIImageView
我开始了一个新线程来下载图像,
但直到我将整个项目下载到我的数据库中时,图像才显示出来!
我试过将 link 放到互联网上的示例图片中,效果还不错 [但有一些延迟]
问题:
1. UIImgeView
没有将其图像设置为直到我加载整个 table。
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];
}
];
}
非常感谢您的帮助..
所有UI相关工作都应该在主线程中完成。
您可能应该执行以下操作:
1) 创建一个图像字典,以 URL 为键,图像为值。使用它来保存加载后的图像副本,因此您只需执行一次。
2) 不要在后台线程中执行任何 UI 更新。使 activity 指示器成为单元格的 属性,以便单元格携带它。随着细胞得到重用!你只需要创建一次。如果单元格图像在字典中并且 activity 不为零,请确保将其删除并停止。如果需要加载图像,请根据需要创建 activity 并添加它。在执行后台加载之前启动指标。
3) 在后台线程中,只做图片的加载。加载后,向主线程同步调用您添加的 imageLoaded 方法,该方法将图像作为参数和加载所针对的单元格 indexPath。在此方法中,将图像添加到您的字典并要求 table 重新加载 indexPath 处的行。这次单个单元格将停止指示器并显示图像,因为它会跟随 2).
这将确保您的单元格在图像到达时更新,并且所有 UI 操作都发生在主线程上。
您需要跟踪哪些图像正在加载,这样您就不会有多个 运行。你已经有这个问题了我认为在你当前的代码中如果有人将一个单元格滚动到屏幕外并返回。
在 UITableViewCell 中加载图像的最佳方式是 AFNetworking UIImageView 类别 class。
将 AFNetworking
库导入您的项目 & UIImageView+AFNetworking
class。
#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];
这将为您异步完成所有事情