博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SDWebImage图片预加载的实现
阅读量:5831 次
发布时间:2019-06-18

本文共 12346 字,大约阅读时间需要 41 分钟。

我SDWebImage库加载远程图片到一个表视图中我创建了一个自定义单元格类。

[cell.imageView setImageWithURL:url placeholderImage:[UIImage imageNamed:@"loading.jpg"]];

现在的问题是它加载在可见单元格的图像,而不是只为我要上下滚动,使它们加载的cell都位于屏幕之外。有没有什么办法可以加载所有的图像,而无需滚动表视图。 在此先感谢!

原文地址: 

 

-------------------------------------------------------------------------------------------------------------------------

1. 如果你想预取行,你可以回应UIScrollViewDelegate方法,以确定何时台滚动完成时,触发的行的预取。您可以执行SDWebImagePrefetcher(在我原来的答复我是类的一个小不屑一顾,但它似乎工作相对现在好了):

- (void)viewDidLoad{ [super viewDidLoad]; // the details don't really matter here, but the idea is to fetch data,  // call `reloadData`, and then prefetch the other images NSURL *url = [NSURL URLWithString:kUrlWithJSONData]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {  if (connectionError) {   NSLog(@"sendAsynchronousRequest error: %@", connectionError);   return;  }  self.objects = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];  [self.tableView reloadData];  [self prefetchImagesForTableView:self.tableView]; }];}// some of the basic `UITableViewDataDelegate` methods have been omitted because they're not really relevant

下面是简单的cellForRowAtIndexPath(不完全相关,但只是表明,如果SDWebImagePrefetcher CodeGo.net,你不必与周围cellForRowAtIndexPath

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ static NSString *cellIdentifier = @"Cell"; CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; NSAssert([cell isKindOfClass:[CustomCell class]], @"cell should be CustomCell"); [cell.customImageView setImageWithURL:[self urlForIndexPath:indexPath] placeholderImage:nil]; [cell.customLabel setText:[self textForIndexPath:indexPath]]; return cell;}

这些UIScrollViewDelegate滚动结束时,预取的方法更多的行

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{ // if `decelerate` was true for `scrollViewDidEndDragging:willDecelerate:` // this will be called when the deceleration is done [self prefetchImagesForTableView:self.tableView];}- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{ // if `decelerate` is true, then we shouldn't start prefetching yet, because // `cellForRowAtIndexPath` will be hard at work returning cells for the currently visible // cells. if (!decelerate)  [self prefetchImagesForTableView:self.tableView];}

你需要一个预取程序。这得到了NSIndexPath对于在可见单元格的每一侧的单元格的值,得到他们的图像URL,然后预取数据。

/** Prefetch a certain number of images for rows prior to and subsequent to the currently visible cells * * @param tableView The tableview for which we're going to prefetch images. */- (void)prefetchImagesForTableView:(UITableView *)tableView{ NSArray *indexPaths = [self.tableView indexPathsForVisibleRows]; if ([indexPaths count] == 0) return; NSIndexPath *minimumIndexPath = indexPaths[0]; NSIndexPath *maximumIndexPath = [indexPaths lastObject]; // they should be sorted already, but if not, update min and max accordingly for (NSIndexPath *indexPath in indexPaths) {  if (indexPath.section < minimumIndexPath.section || (indexPath.section == minimumIndexPath.section && indexPath.row < minimumIndexPath.row)) minimumIndexPath = indexPath;  if (indexPath.section > maximumIndexPath.section || (indexPath.section == maximumIndexPath.section && indexPath.row > maximumIndexPath.row)) maximumIndexPath = indexPath; } // build array of imageURLs for cells to prefetch NSMutableArray *imageURLs = [NSMutableArray array]; indexPaths = [self tableView:tableView priorIndexPathCount:kPrefetchRowCount fromIndexPath:minimumIndexPath]; for (NSIndexPath *indexPath in indexPaths)  [imageURLs addObject:[self urlForIndexPath:indexPath]]; indexPaths = [self tableView:tableView nextIndexPathCount:kPrefetchRowCount fromIndexPath:maximumIndexPath]; for (NSIndexPath *indexPath in indexPaths)  [imageURLs addObject:[self urlForIndexPath:indexPath]]; // now prefetch if ([imageURLs count] > 0) {  [[SDWebImagePrefetcher sharedImagePrefetcher] prefetchURLs:imageURLs]; }}

这些是用于获取NSIndexPath对于前可见单元格,以及那些跟随可见单元格的行:

/** Retrieve NSIndexPath for a certain number of rows preceding particular NSIndexPath in the table view. * * @param tableView The tableview for which we're going to retrieve indexPaths. * @param count  The number of rows to retrieve * @param indexPath The indexPath where we're going to start (presumably the first visible indexPath) * * @return   An array of indexPaths. */- (NSArray *)tableView:(UITableView *)tableView priorIndexPathCount:(NSInteger)count fromIndexPath:(NSIndexPath *)indexPath{ NSMutableArray *indexPaths = [NSMutableArray array]; NSInteger row = indexPath.row; NSInteger section = indexPath.section; for (NSInteger i = 0; i < count; i++) {  if (row == 0) {   if (section == 0) {    return indexPaths;   } else {    section--;    row = [tableView numberOfRowsInSection:section] - 1;   }  } else {   row--;  }  [indexPaths addObject:[NSIndexPath indexPathForRow:row inSection:section]]; } return indexPaths;}/** Retrieve NSIndexPath for a certain number of following particular NSIndexPath in the table view. * * @param tableView The tableview for which we're going to retrieve indexPaths. * @param count  The number of rows to retrieve * @param indexPath The indexPath where we're going to start (presumably the last visible indexPath) * * @return   An array of indexPaths. */- (NSArray *)tableView:(UITableView *)tableView nextIndexPathCount:(NSInteger)count fromIndexPath:(NSIndexPath *)indexPath{ NSMutableArray *indexPaths = [NSMutableArray array]; NSInteger row = indexPath.row; NSInteger section = indexPath.section; NSInteger rowCountForSection = [tableView numberOfRowsInSection:section]; for (NSInteger i = 0; i < count; i++) {  row++;  if (row == rowCountForSection) {   row = 0;   section++;   if (section == [tableView numberOfSections]) {    return indexPaths;   }   rowCountForSection = [tableView numberOfRowsInSection:section];  }  [indexPaths addObject:[NSIndexPath indexPathForRow:row inSection:section]]; } return indexPaths;}

有很多在那里,但在现实中,SDWebImageSDWebImagePrefetcher是做繁重。 里面含有的缘故低于我原来的答复 原来的答案: 如果你想要做的与预取SDWebImage,你可以做如下所示: 添加块到您的setImageWithURL调用:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ NSLog(@"%s", __FUNCTION__); static NSString *cellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; TableModelRow *rowData = self.objects[indexPath.row]; cell.textLabel.text = rowData.title; [cell.imageView setImageWithURL:rowData.url     placeholderImage:[UIImage imageNamed:@"placeholder.png"]       completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {        [self prefetchImagesForTableView:tableView];       }]; return cell;}

我必须承认,我真的不喜欢我打电话prefetcher常规这里(我希望iOS的有很好的didFinishTableRefresh但它的作品,即使它调用例程超过我真正想要的。我只是确保低于下面的程序可以确保它不会让多余的请求。 反正我写一个程序预取,看起来,比如说,未来十年的影像:

const NSInteger kPrefetchRowCount = 10;- (void)prefetchImagesForTableView:(UITableView *)tableView{ // determine the minimum and maximum visible rows NSArray *indexPathsForVisibleRows = [tableView indexPathsForVisibleRows]; NSInteger minimumVisibleRow = [indexPathsForVisibleRows[0] row]; NSInteger maximumVisibleRow = [indexPathsForVisibleRows[0] row]; for (NSIndexPath *indexPath in indexPathsForVisibleRows) {  if (indexPath.row < minimumVisibleRow) minimumVisibleRow = indexPath.row;  if (indexPath.row > maximumVisibleRow) maximumVisibleRow = indexPath.row; } // now iterate through our model; // `self.objects` is an array of `TableModelRow` objects, one object // for every row of the table. [self.objects enumerateObjectsUsingBlock:^(TableModelRow *obj, NSUInteger idx, BOOL *stop) {  NSAssert([obj isKindOfClass:[TableModelRow class]], @"Expected TableModelRow object");  // if the index is within `kPrefetchRowCount` rows of our visible rows, let's  // fetch the image, if it hasn't already done so.  if ((idx < minimumVisibleRow && idx >= (minimumVisibleRow - kPrefetchRowCount)) ||   (idx > maximumVisibleRow && idx <= (maximumVisibleRow + kPrefetchRowCount)))  {   // my model object has method for initiating a download if needed   [obj downloadImageIfNeeded];  } }];}

在下载程序中,您可以检查,看看图像下载已经开始,如果没有,则启动它。要做到这一点有SDWebImage,我保持weak指针在网页图像处理我的TableModelRow类(即备份我的表的各行的模型类):

@property (nonatomic, weak) id
webImageOperation;

然后我有downloadImageIfNeeded程序开始下载,如果它还没有(你就会明白为什么做了weak是如此重要......我检查,看看这行已经有另一个开始之前的操作挂起)。我不这样做与下载图像(短的,用于调试目的,记录的事实,下载已完成),而只是下载,让任何事情SDImageWeb保持缓存图像的轨道,所以当cellForRowAtIndexPath后来要求形象向下滚动,它的存在,准备和等待。

- (void)downloadImageIfNeeded{ if (self.webImageOperation)  return; SDWebImageManager *imageManager = [SDWebImageManager sharedManager]; self.webImageOperation = [imageManager downloadWithURL:self.url             options:0             progress:nil             completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished) {              NSLog(@"%s: downloaded %@", __FUNCTION__, self.title);              // I'm not going to do anything with the image, but `SDWebImage` has now cached it for me             }];}

部分认为它可能更叫imageManager.imageCachequeryDiskCacheForKey优先,做测试后,它看起来并不像是一个需要(和downloadWithURL确实是这样)。 我要指出的是,SDImageWeb库有SDWebImagePrefetcher类(请参阅类的的是令人难以置信的前途,但看代码,与所有尊重一个原本优秀的库,这不会觉得很(例如,它的网址是一个简单的列表来获取,如果你再这样做,它取消了之前列表“添加到队列”或类似的东西)的概念。这是一个有前途的概念,但在执行有点弱,而当我试了一下,我UX遭受明显。 所以,我倾向于SDWebImagePrefetcher(直到它的改善,至少),并坚持我的预取技术。它并不十分复杂,但它似乎工作。 

2. 这是一个例子,你需要这样你的目的。 您的UITableView的委托:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ YourCustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"YourCustomTableViewCellReuseIdentifier"]; if (!cell) {  cell = [[[YourCustomTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault        reuseIdentifier:CellIdentifier];   } NSString *imageURL = // ... get image url, typically from array [cell loadImageWithURLString:imageURL forIndexPath:indexPath];  return cell;}

,您的自定义的UITableViewCell h文件:

#import 
#import "UIImageView+WebCache.h"#import "SDImageCache.h"@interface YourCustomTableViewCell{ NSIndexPath *currentLoadingIndexPath;}- (void)loadImageWithURLString:(NSString *)urlString forIndexPath:(NSIndexPath *)indexPath;@end

,您的自定义的UITableViewCell m文件:

// ... some other methods- (void)loadImageWithURLString:(NSString *)urlString forIndexPath:(NSIndexPath *)indexPath{ currentLoadingIndexPath = indexPath; [self.imageView cancelCurrentImageLoad]; [self.imageView setImage:nil]; NSURL *imageURL = [NSURL URLWithString:urlString]; [self.imageView setImageWithURL:imageURL     placeholderImage:nil       options:SDWebImageRetryFailed       completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {  if (currentLoadingIndexPath != indexPath)  {   return;  }  if (error)  {   ... // handle error  }  else  {   [imageView setImage:image];  } }];}// ... some other methods

currentLoadingIndexPath如果我们检测到该小区的另一幅图像,而不是将其下载滚动表视图图像所需。 

3. 我必须解决这个确切的问题,不想预取的开销。必须有额外的下引擎罩的事情发生与防止装载内置ImageView的属性,一个新的UIImageView工作得很好。 我的解决方案是非常干净的,如果你不使用的UITableViewCell的子类介意(或已经): 子类的UITableViewCell。 在你的子类,隐藏self.imageView。 创建您自己的UIImageView子视图,并设置该视图的形象。 下面是我自己的代码(这里是设置到了iOS照片应用程序的相册的大小和位置匹配覆盖)的修改版本: YourTableCell.h

@interface YourTableCell : UITableViewCell @property (nonatomic, strong) UIImageView *coverPhoto;@end

YourTableCell.m

@implementation YourTableCell@synthesize coverPhoto;- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{ self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) {  self.imageView.image = nil;  self.coverPhoto = [[UIImageView alloc] init];  // Any customization, such as initial image, frame bounds, etc. goes here.    [self.contentView addSubview:self.coverPhoto]; } return self;}//...@end

YourTableViewController.m

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ static NSString *CellIdentifier = @"Cell"; YourTableCell *cell = (YourTableCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier]; //... [cell.coverPhoto setImageWithURL:coverUrl placeholderImage:nil options:SDWebImageCacheMemoryOnly]; //...}

转载于:https://www.cnblogs.com/zhaoyanpeng/p/4829667.html

你可能感兴趣的文章
8个令人印象深刻的JavaScript效果的网站
查看>>
使用SocketAsyncEventArgs犯的低级错误
查看>>
推荐25个强大的 jQuery 网页布局设计作品欣赏
查看>>
信息时代下,如何看待技术与理论
查看>>
NYOJ 503(牛顿迭代)
查看>>
NYOJ 63(小猴子下落)
查看>>
JS浮点数相乘运算解决误差的方法 转载
查看>>
c++安全释放资源
查看>>
javascript 编程规范
查看>>
MVC中如何设置路由指定默认页
查看>>
何如获取单选框中某一个选中的值
查看>>
paip.输入法编程----删除双字词简拼
查看>>
Struct2、Hibernate3、Spring3框架搭建实战(转)
查看>>
同步、异步、阻塞和非阻塞的概念
查看>>
为什么在我眼里你是一只傻逼——傻逼“常所用”句型之(1)——“就算……但是……”...
查看>>
Node_JS
查看>>
数据库选项--数据库状态
查看>>
简记微软实习生面试
查看>>
#linux包之tcpdump之tcpdump命令
查看>>
Hadoop的数据管理
查看>>