我已经使用apple here提供的示例在我的应用中成功实现了图像的延迟加载。问题是,我想在我滚动时加载图像,但只有当我完成拖动时才将图像加载到单元格中(从屏幕上释放我的手指。此时单元格保持为空)。我修改了代码如下:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//NSLog(@"cell for row at indexpath, size - %f, current - %d", flowTable.contentSize.height, self.current);
NSString *CellIdentifier = @"FlowCell";
MyFlowCell *cell = (MyFlowCell *)[self.flowTable dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"FlowCell" owner:nil options:nil];
// cell = [nib objectAtIndex:0];
for(id currentObject in nib)
{
if([currentObject isKindOfClass:[MyFlowCell class]])
{
cell = (MyFlowCell *)currentObject;
break;
}
}
}
ImageDetails *rowItem = [self.imageData objectAtIndex:indexPath.row];
if (!rowItem.mainImage)
{
// if (self.flowTable.dragging == NO && self.flowTable.decelerating == NO)
// {
[self startIconDownload:rowItem forIndexPath:indexPath];
//}
cell.mainImage.backgroundColor = [UIColor grayColor];
}
else
{
cell.mainImage.image = rowItem.mainImage;
}
}
return cell;
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
if (!decelerate)
{
// [self loadImagesForOnscreenRows];
}
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
//[self loadImagesForOnscreenRows];
}
此外,我发现在我的ImageDownloader类中,NSURLConnection甚至都没有收到响应,直到我从屏幕上释放手指。我一直试图找出为什么会这样,但到目前为止我还没有成功。如果我错过了什么,请告诉我。
答案 0 :(得分:9)
更新回答:
标准Apple LazyTableImages存在一些缺陷:
在滚动完成之前,它不会尝试检索图像。我明白为什么他们选择这样做(可能不想检索可能会滚动的图像),但这会导致图像显得比必要的慢。
它不会将并发请求的数量限制为某个合理的数量。是的,NSURLConnection
将自动冻结请求,直到最大请求数降至某个合理数量,但在最坏的情况下,您实际上可以请求超时,而不是简单地排队。
一旦开始下载图像,即使单元格随后滚出屏幕,也不会取消图像。
简单的解决方法是退出IconDownloader
和所有滚动/减速逻辑,只使用SDWebImage
或AFNetworking
中的UIImageView
类别。
如果您要自己修复此问题,需要做一些工作才能完成所有这些工作。但here is a rendition of LazyTableImages使用NSOperationQueue
来确保我们(a)限制并发请求; (b)允许我们取消请求。我承认我更喜欢上面的UIImageView
类别实现,但是我试图继续使用Apple原始LazyTableImages
的结构,同时补救我上面列举的缺陷。
答案 1 :(得分:8)
您可以按照以下步骤在tableview中实现延迟加载:
在Class.h中,输入:
NSMutableDictionary *Dict_name;
BOOL isDragging_msg, isDecliring_msg;
现在在Class.m文件中,将此代码放入视图中加载:
Dict_name = [[NSMutableDictionary alloc] init];
在cellForRowAtIndexPath中:
if ([dicImages_msg valueForKey:[[msg_array objectAtIndex:indexPath.row] valueForKey:@"image name or image link"]]) {
cell.image_profile.image=[dicImages_msg valueForKey:[[msg_array objectAtIndex:indexPath.row] valueForKey:@"image name or image link"]];
}
else
{
if (!isDragging_msg && !isDecliring_msg)
{
[dicImages_msg setObject:[UIImage imageNamed:@"Placeholder.png"] forKey:[[msg_array objectAtIndex:indexPath.row] valueForKey:@"image name or image link"]];
[self performSelectorInBackground:@selector(downloadImage_3:) withObject:indexPath];
}
else
{
cell.image_profile.image=[UIImage imageNamed:@"Placeholder.png"];
}
}
对于下载图像,功能是:
-(void)downloadImage_3:(NSIndexPath *)path{
NSAutoreleasePool *pl = [[NSAutoreleasePool alloc] init];
NSString *str=[here Your image link for download];
UIImage *img = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:str]]];
[dicImages_msg setObject:img forKey:[[msg_array objectAtIndex:path.row] valueForKey:@"image name or image link same as cell for row"]];
[tableview performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];
[pl release];
}
最后将这些方法放在你的班级中:
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
isDragging_msg = FALSE;
[tableview reloadData];
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
isDecliring_msg = FALSE;
[tableview reloadData];
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
isDragging_msg = TRUE;
}
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView{
isDecliring_msg = TRUE;
}
答案 2 :(得分:1)
假设您的UITableViewCell具有url属性和图像的UIImage属性(加上队列的属性或静态值:
- (void) setThumbnailUrlString:(NSString *)urlString
{
thumbnailUrlString = urlString;
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
if ( queue == nil )
{
queue = [[NSOperationQueue alloc] init];
}
[NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse * resp, NSData *data, NSError *error)
{
dispatch_async(dispatch_get_main_queue(),^
{
if ( error == nil && data )
{
UIImage *urlImage = [[UIImage alloc] initWithData:data];
thumbnail.image = urlImage;
}
});
}];
}
您的实现问题是您的图像加载方法可能发生在主线程中。您需要异步加载图像,然后在主线程中更新图像。
为了更正,如果在将单元格重新用于其他图像之前,单元格的图像加载太晚,则块应检查响应的url是否与请求的url匹配。
答案 3 :(得分:0)
我已经完成了这个包含延迟加载控制器的框架。它易于使用,开箱即用。 https://github.com/cloverstudio/CSUtils 教程可以在这里找到: http://www.clover-studio.com/blog/using-csutils-ios-framework-for-lazy-loading-images/
答案 4 :(得分:0)
这是一个很晚的答案,但随着iOS版本的改变,这种方法不断变化。
为了懒洋洋地加载图像,这是推荐的方法:
此处 - 整个方法为described in my tutorial。