我正在使用SDWeb Image库将远程映像加载到使用我创建的自定义单元格的表视图中.我只是用
[cell.imageView setimageWithURL:url placeholderImage:[UIImage imageNamed:@"loading.jpg"]];

in cellForRowAtIndexPath:
现在的问题是它只加载可见单元格中的图像,而不是为了我不得不向上和向下滚动以使其加载的屏幕外的单元格.有没有办法我可以加载所有的图像,而不必滚动表视图.
提前致谢!!

解决方法

如果要预取行,则可以响应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,你不必乱七八糟的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;
}

这里有很多,但实际上,SDWebImage及其SDWebImagePrefetcher正在大力提升.

为了完整起见,我将原来的答案包括在内.

原来的答案:

如果要使用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;
}

我必须承认,我不喜欢在这里调用我的预取程序(我希望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执行此操作,我在TableModelRow类(支持表的各行的模型类)中保留一个弱指针到web图像操作:

@property (nonatomic,weak) id<SDWebImageOperation> webImageOperation;

如果还没有,请下载downloadImageIfNeeded例程(您可以看到为什么这个弱点非常重要)我正在检查这个行是否已经有一个操作挂起,然后再启动另一个).我没有对下载的图像做任何事情(简而言之,为了调试目的,记录下载完成的事实),而只是下载并让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,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.imageCache实例方法querydiskCacheForKey可能会更加强大,但是在进行了一些测试之后,它看起来不像那样(而且对于我们来说,downloadWithURL对我们来说是这样).

我应该指出,SDImageWeb库确实有一个SDWebImagePrefetcher类(见the documentation).类的名称是非常有希望的,但是看代码,所有的尊重,否则优秀的图书馆,这对我来说并不觉得非常强大(例如,这是一个简单的URL提取列表,如果你再次这样做,它取消了先前的列表,没有“添加到队列”或任何类似的概念.这是一个有希望的概念,但执行有点薄弱.当我尝试它,我的UX受到明显的影响.

所以,我倾向于不使用SDWebImagePrefetcher(至少要改进),并且坚持我的基本预取技术.这不是非常复杂的,但它似乎工作.

ios – SDWebImage不会加载远程图像,直到滚动的更多相关文章

  1. 移动HTML5前端框架—MUI的使用

    这篇文章主要介绍了移动HTML5前端框架—MUI的使用的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. HTML5 weui使用笔记

    这篇文章主要介绍了HTML5 weui使用笔记,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  3. Html5写一个简单的俄罗斯方块小游戏

    这篇文章主要介绍了基于Html5写一个简单的俄罗斯方块小游戏,本文通过图文并茂的形式给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友参考下吧

  4. ios – UITableView和Cell Reuse

    这是我的CustomCell类的init方法解决方法如果没有要显示的图像,则必须清除图像视图:

  5. ios – fetchedResultsController.fetchedObjects.count = 0但它充满了对象

    我正在使用相当标准的fetchedResultsController实现来输出tableView.在-viewDidLoad的最后,我正在进行第一次调用:这是我的fetchedResultsController:我的tableView方法:所以,问题是:在_fetchedResultsController.fetchedobjects.count的日志中等于0,但在视觉上tableView充满了对

  6. ios – 如何实现`prepareForReuse`?

    解决方法尝试将此添加到您的MGSwipeTableCell.m:

  7. ios – 我的表视图在滚动时在SWIFT中重用所选单元格

    实例变量

  8. ios – 在uicollectionview底部添加加载指示符

    解决方法不,没有“内置”的方式.您需要做的是有一个包含加载器的额外单元格.检测此单元格何时出现非常简单,此时您可以启动调用以加载更多数据.

  9. ios – CFNetwork内部错误:URLConnectionLoader.cpp:289

    当我在一段时间后打开我的应用程序时,我收到了日志:440:CFNetworkinternalerror(0xc01a:/buildroot/Library/Caches/com.apple.xbs/Sources/CFNetwork/CFNetwork-758.4.3/Loading/URLConnectionLoader.cpp:289)它从未出现在过去.我的项目使用网络库AFNetworkin

  10. ios – UICollectionView神秘崩溃

    我有一个UICollectionView,我用从Internet下载的图像填充单元格.为此我使用SDWebImage.我的代码如下所示:我相信我已经正确地设置了它.但应用程序完全随机崩溃,有时会留下此堆栈跟踪:日志区域中没有其他消息.我尝试设置异常断点,但每次发生此崩溃时,都会显示此堆栈跟踪.有谁知道可能是什么问题?解决方法如果有人在寻找答案,我已经解决了问题,并回答了与同一问题有关的另一个问题.你可以找到它here.希望它有所帮助!

随机推荐

  1. iOS实现拖拽View跟随手指浮动效果

    这篇文章主要为大家详细介绍了iOS实现拖拽View跟随手指浮动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  2. iOS – genstrings:无法连接到输出目录en.lproj

    使用我桌面上的项目文件夹,我启动终端输入:cd然后将我的项目文件夹拖到终端,它给了我路径.然后我将这行代码粘贴到终端中找.-name*.m|xargsgenstrings-oen.lproj我在终端中收到此错误消息:genstrings:无法连接到输出目录en.lproj它多次打印这行,然后说我的项目是一个目录的路径?没有.strings文件.对我做错了什么的想法?

  3. iOS 7 UIButtonBarItem图像没有色调

    如何确保按钮图标采用全局色调?解决方法只是想将其转换为根注释,以便为“回答”复选标记提供更好的上下文,并提供更好的格式.我能想出这个!

  4. ios – 在自定义相机层的AVFoundation中自动对焦和自动曝光

    为AVFoundation定制图层相机创建精确的自动对焦和曝光的最佳方法是什么?

  5. ios – Xcode找不到Alamofire,错误:没有这样的模块’Alamofire’

    我正在尝试按照github(https://github.com/Alamofire/Alamofire#cocoapods)指令将Alamofire包含在我的Swift项目中.我创建了一个新项目,导航到项目目录并运行此命令sudogeminstallcocoapods.然后我面临以下错误:搜索后我设法通过运行此命令安装cocoapodssudogeminstall-n/usr/local/bin

  6. ios – 在没有iPhone6s或更新的情况下测试ARKit

    我在决定下载Xcode9之前.我想玩新的框架–ARKit.我知道要用ARKit运行app我需要一个带有A9芯片或更新版本的设备.不幸的是我有一个较旧的.我的问题是已经下载了新Xcode的人.在我的情况下有可能运行ARKit应用程序吗?那个或其他任何模拟器?任何想法或我将不得不购买新设备?解决方法任何iOS11设备都可以使用ARKit,但是具有高质量AR体验的全球跟踪功能需要使用A9或更高版本处理器的设备.使用iOS11测试版更新您的设备是必要的.

  7. 将iOS应用移植到Android

    我们制作了一个具有2000个目标c类的退出大型iOS应用程序.我想知道有一个最佳实践指南将其移植到Android?此外,由于我们的应用程序大量使用UINavigation和UIView控制器,我想知道在Android上有类似的模型和实现.谢谢到目前为止,guenter解决方法老实说,我认为你正在计划的只是制作难以维护的糟糕代码.我意识到这听起来像很多工作,但从长远来看它会更容易,我只是将应用程序的概念“移植”到android并从头开始编写.

  8. ios – 在Swift中覆盖Objective C类方法

    我是Swift的初学者,我正在尝试在Swift项目中使用JSONModel.我想从JSONModel覆盖方法keyMapper,但我没有找到如何覆盖模型类中的Objective-C类方法.该方法的签名是:我怎样才能做到这一点?解决方法您可以像覆盖实例方法一样执行此操作,但使用class关键字除外:

  9. ios – 在WKWebView中获取链接URL

    我想在WKWebView中获取tapped链接的url.链接采用自定义格式,可触发应用中的某些操作.例如HTTP://我的网站/帮助#深层链接对讲.我这样使用KVO:这在第一次点击链接时效果很好.但是,如果我连续两次点击相同的链接,它将不报告链接点击.是否有解决方法来解决这个问题,以便我可以检测每个点击并获取链接?任何关于这个的指针都会很棒!解决方法像这样更改addobserver在observeValue函数中,您可以获得两个值

  10. ios – 在Swift的UIView中找到UILabel

    我正在尝试在我的UIViewControllers的超级视图中找到我的UILabels.这是我的代码:这是在Objective-C中推荐的方式,但是在Swift中我只得到UIViews和CALayer.我肯定在提供给这个方法的视图中有UILabel.我错过了什么?我的UIViewController中的调用:解决方法使用函数式编程概念可以更轻松地实现这一目标.

返回
顶部