【问题标题】:NSURLSession for network images download+cacheNSURLSession 用于网络图片下载+缓存
【发布时间】:2018-02-21 23:46:28
【问题描述】:

有许多第三方库用于加载网络映像,然后将其存储到磁盘和/或内存中。

但是使用简单的 NSURLSession API 调用实现它非常容易

代码如下:

     NSURLCache *myCache = [[NSURLCache alloc] initWithMemoryCapacity: 16384 diskCapacity: 268435456 diskPath: cachePath]; // these numbers are only for the usage example.
     defaultConfigObject.URLCache = myCache;
     defaultConfigObject.requestCachePolicy = NSURLRequestUseProtocolCachePolicy;
     _session = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate:self delegateQueue: [NSOperationQueue mainQueue]];

     _dataTask = [_session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){

        if (!error){
            UIImage* theImage = [UIImage imageWithData:data];
            dispatch_async(dispatch_get_main_queue(), ^{
                self.image = theImage;

            });
        }
    }];
    [_dataTask resume];

此代码下载图像(从给定的 url)并根据 http 缓存策略将其存储到内存+磁盘。

从 UIImageView 派生 MyNetworkImageView 并将上述代码添加到 setURL: 方法,也很简单。

我的问题是

使用AFNetworking、FastImageCache、SDWebImage、SDImageCache等其他第三方框架有什么优势?

【问题讨论】:

  • NSURLSession 中的缓存取决于 (a) 相对于缓存大小的下载大小; (b) 响应的标头。我真的会对你的应用程序进行压力测试,并确保缓存(尤其是持久存储缓存)像你想象的那样工作。您的内存缓存似乎非常小(任何超过缓存大小 5% 的内容都不会被缓存)。最重要的是,过去在 iOS 中依赖 NSURLCache 一直存在问题,尤其是在您不控制服务器的情况下。这些类也提供其他优势(例如,UIImageView 类别)。
  • 谢谢罗伯。我已经根据您的评论编辑了我的问题。关于内存缓存大小,仅作为使用示例,没有实际的工作编号。关于 iOS 中的 NSURLCache 问题,我记得这些问题,但我相信它们在 iOS8 及更高版本中不再相关。最后,假设服务器定义了缓存行为,还有更多的优势吗?
  • 好的。我通常希望内存缓存以 MB 为单位,而不是 KB。 :) 通过NSURLCache 重新缓存成功,我只建议先凭经验验证这一点。但是,如果 NSURLSession 满足您的需求,那么请继续使用它。我会退后一步考虑一下应用程序更广泛的网络需求,但如果您不需要复杂的 HTTP 请求创建/处理,也不需要 UIImageView 类别等,那么请坚持使用 NSURLSession

标签: ios afnetworking sdwebimage


【解决方案1】:
  1. 这些框架中的缓存更具确定性。 NSURLSession 使用的 NSURLCache (a) 有点不透明(例如,我从未见过 5% 的阈值记录在案); (b) 由您的服务器提供的响应标头控制。

  2. 在您简单地声明 NSURLCache“足够好”之前,我建议严格测试应用程序并确保缓存(尤其是持久存储缓存:运行应用程序、下载图像;终止(不仅仅是暂停)应用程序;重新运行应用程序)正在像您希望的那样工作。确保测试运行时缓存和持久存储缓存。

  3. 顺便说一句,您的内存缓存似乎非常小(超过缓存大小 5% 的任何内容都不会被缓存)。这是一个见仁见智的问题,但我通常希望看到接近 16mb 而不是 16kb 的东西。事实上,这不会缓存任何超过 800 字节左右的内容!

  4. 这些框架还提供了许多其他优势。

    • AFNetworking 和 SDWebImage 提供的UIImageView 类别是实现异步图像检索的最简单方法。特别是在表格/集合视图中重用单元格时,它将取消先前的请求,确保对可见单元格的图像请求优先。 (您不希望快速滚动到表格中的第 100 行,并且必须等待 99 个不可见图像下载后才能开始下载可见单元格的图像。)

    • 如果生成复杂的 HTTP 请求,AFNetworking 让您可以专注于应用逻辑,而不是编写和测试复杂的网络代码。

底线,过去在 iOS 中依赖 NSURLCache 是有问题的,尤其是在你不控制服务器的情况下。这些类也提供其他优势(例如,使用 UIImageView 类别)。

【讨论】:

  • 如果我错了,请纠正我,但 AFNetworking 也使用 NSURLCache(默认情况下不缓存到磁盘):github.com/AFNetworking/AFNetworking/wiki/AFNetworking-FAQ
  • @user2955669 - AFNetworking 的UIImageView 类别也使用自己的手册NSCache。但是,是的,在它下面也有NSURLCache 功能。但是您可以通过NSURLCache 缓存到磁盘(例如,受到NSURLCache 的所有约束和限制)。 SDWebImage 自己做持久化存储缓存,上次我用过。
  • 还要注意“NSURLConnection 在 iOS9 中已被弃用”(developer.apple.com/videos/wwdc/2015/?id=711),它仍然可以工作,但最终会结束。 AFNetworking 仍然使用 NSURLConnection,但必须修改为仅在 NSURLSession 之上工作,因此与 NSURLConnection API 相比,AFNetworking API 的优势(例如基于块的 API)也将被弃用。
  • 同意。因此,如果您不需要向后兼容较旧的操作系统版本,并且您可以接受NSURLCache 的限制,那么在NSURLSession 中做一些事情是个好主意。但是您需要的东西比您在上面的问题中所考虑的要丰富得多,因为缓存只是众多考虑因素之一,例如优先考虑可见图像,因此当您快速滚动浏览图像时,网络连接速度较慢,不会出现积压、限制并发度、预取/预热等)。
【解决方案2】:

NSURLCache 是一个很棒的工具,尤其是当您需要重新验证机制时,NSURLCache 会为您透明地处理 HTTP 重新验证。 NSURLSession 也是一个很好的 Cocoa 网络step forward

但是,以一种有效的方式实现图像提取并不是那么容易。您的应用可能有一些特殊要求:

  1. 避免在主线程上进行图像解压,代价高昂,尤其是对于 jpg。
  2. 在 NSURLCache 之上有一个单独的内存缓存层来存储解压缩的图像,并能够在主线程上同步检索它们。管理内存缓存也不是那么简单,即使你使用 NSCache。
  3. 在网络层的顶部有一些抽象,以便能够在必要时添加对更多图像格式的支持,例如gifwebp。并以其他方式扩展图像获取。
  4. 对相同的图像请求进行分组,不要创建过多的会话任务
  5. 能够高效地preheat images
  6. 有办法先获取低分辨率占位符,然后等待高分辨率图像

还有更多。

AFNetworking、FastImageCache、SDWebImage、SDImageCache

这些框架都不使用 NSURLSession(有些甚至有自己的磁盘缓存实现),请查看 Nuke / DFImageManager。它建立在 NSURLSession 之上,具有上述所有功能,并且还具有多个子规范,将 AFNetworking* 作为网络堆栈、FLAnimatedImage 作为动画 GIF 引擎等等。

*AFNetworking 是基于 NSRULSession,但他们的图片获取实现仍然基于 NSURLConnection (AFHTTPRequestOperation)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-11
    • 1970-01-01
    相关资源
    最近更新 更多