图片在APP中占有重要的角色,对图片做好缓存是重要的一项工作。[TOC]

理论

不喜欢理论的可以直接跳到下面的Demo实践部分

缓存介绍

缓存按照保存位置可以分为两类:内存缓存、硬盘缓存(FMDB、CoreData…)。我们常说的网络请求缓存包含内存缓存、硬盘缓存和URL缓存。

图片缓存思路

网络请求缓存

网络请求出了客户端需要做简单的配置外,最主要需要服务器支持,服务端也很简单,只需要在response里面设置Cache-Control字段就行了.

最常见的网络请求缓存实现方式:NSURLCache。NSURLCache可以在memory 和 disk 上缓存。AFNetWorking是基于NSURLSession,在生成配置的时候有三种配置选择

+ (NSURLSessionConfiguration *)defaultSessionConfiguration;  
//默认会话模式(default):工作模式类似于原来的NSURLConnection,使用的是基于磁盘缓存的持久化策略,使用用户keychain中保存的证书进行认证授权。
+ (NSURLSessionConfiguration *)ephemeralSessionConfiguration;  
//瞬时会话模式(ephemeral):该模式不使用磁盘保存任何数据。所有和会话相关的caches,证书,cookies等都被保存在RAM中,因此当程序使会话无效,这些缓存的数据就会被自动清空。
+ (NSURLSessionConfiguration *)backgroundSessionConfiguration:(NSString *)identifier;  
//后台会话模式(background):该模式在后台完成上传和下载,在创建Configuration对象的时候需要提供一个NSString类型的ID用于标识完成工作的后台会话。

也就是说default同时实现了内存缓存和硬盘缓存,ephemeral实现了内存缓存,对于图片下载我们当然选择default。我们还可以对缓存的大小进行设置,只需要对NSURLCache进行初始化就可以了

实现初始化

在-application:didFinishLaunchingWithOptions:中对[NSURLCache sharedURLCache]进行初始化设置:

NSURLCache *URLCache = [[NSURLCache alloc] initWithMemoryCapacity:4 * 1024 * 1024
                                                     diskCapacity:20 * 1024 * 1024
                                                         diskPath:nil];
[NSURLCache setSharedURLCache:URLCache];

也可以单独对NSURLSession的configuration进行设置,在AFNetWorking中对于图片网络请求设置了20M的内存缓存和150M的硬盘缓存:

+ (NSURLCache *)defaultURLCache {
    return [[NSURLCache alloc] initWithMemoryCapacity:20 * 1024 * 1024
                                         diskCapacity:150 * 1024 * 1024
                                             diskPath:@"com.alamofire.imagedownloader"];
}

缓存策略

缓存策略是指对网络请求缓存如果处理,是使用缓存还是不使用

NSURLRequestUseProtocolCachePolicy: 对特定的 URL 请求使用网络协议中实现的缓存逻辑。这是默认的策略。
NSURLRequestReloadIgnoringLocalCacheData:数据需要从原始地址加载。不使用现有缓存。
NSURLRequestReloadIgnoringLocalAndRemoteCacheData:不仅忽略本地缓存,
      同时也忽略代理服务器或其他中间介质目前已有的、协议允许的缓存。
NSURLRequestReturnCacheDataElseLoad:无论缓存是否过期,先使用本地缓存数据。
      如果缓存中没有请求所对应的数据,那么从原始地址加载数据。
NSURLRequestReturnCacheDataDontLoad:无论缓存是否过期,先使用本地缓存数据。
      如果缓存中没有请求所对应的数据,那么放弃从原始地址加载数据,
      请求视为失败(即:“离线”模式)。
NSURLRequestReloadRevalidatingCacheData:从原始地址确认缓存数据的合法性后,
      缓存数据就可以使用,否则从原始地址加载。

在AFNetWorking中同样对configuration进行设置

configuration.requestCachePolicy = NSURLRequestUseProtocolCachePolicy;

如果你继承AFImageDownloader重新实现了他的初始化,requestCachePolicy注意AFImageDownloader中只有三种才设置了缓存

case NSURLRequestUseProtocolCachePolicy:
case NSURLRequestReturnCacheDataElseLoad:
case NSURLRequestReturnCacheDataDontLoad:

内存缓存

AFNetWorking3.0放弃了NSCache作为图片内存缓存管理,这让我非常不解。有人说它的性能和 key 的相似度有关,如果有大量相似的 key (比如 “1”, “2”, “3”, …),NSCache 的存取性能会下降得非常厉害,大量的时间被消耗在 CFStringEqual() 上,不知这是不是放弃使用NSCache的原因。

像素在内存中的布局和它在磁盘中的存储方式并不相同。考虑一种简单的情况:每个像素有R、G、B和alpha四个值,每个值占用1字节,因此每个像素占用4字节的内存空间。一张1920*1080的照片(iPhone6 Plus的分辨率)一共有2,073,600个像素,因此占用了超过8Mb的内存。但是一张同样分辨率的PNG格式或JPEG格式的图片一般情况下不会有这么大。这是因为JPEG将像素数据进行了一种非常复杂且可逆的转化。

AFNetWorking3.0的图片缓存类貌似是基于这个理论来做内存大小管理的(之前AF的内存大小计算方法有错,我修改了一下提交了,现在已经审核通过合并进去了,哈哈哈哈哈,我也算是贡献过AF了)。AFNetWorking2.x中还是使用AFImageCache进行memory上缓存。

NSCache在memory上缓存,类似于NSMutableDictionary ,以 哈希算法 管理。有自动清理机制,当缓存到memory时,如果memory空间不够,则会自动删除memory中当前界面不使用的空间。

AFAutoPurgingImageCache使用NSMutableDictionary<nsstring*>进行内存缓存映射,并进行管理,当内存警告时就清空NSMutableDictionary。如果内存占用超过限制,则按照时间顺序进行删除。

硬盘缓存

就是我们常说的把数据保存在本地,比如FMDB,CoreData,归档,NSUserDefaults,NSFileManager等等,这里就不多说了。图片缓存建议使用NSFileManager,因为一般图片data会比较大,测试证明路径缓存会比放在数据库有更高的性能。

实践

Demo下载

https://github.com/SummertimSadness/AFUIImageDemo

使用NSURLSession做网络请求缓存。

    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];     //使用default配置,自带网络请求缓存
    [config setHTTPAdditionalHeaders:@{@"Accept":@"image/*"}];//设置网络数据格式
    NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    WEAKSELF
    NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { //使用’获取数据(NSURLSessionDataTask)‘的方式发起请求
        UIImage *image = [UIImage imageWithData:data];
        dispatch_async(dispatch_get_main_queue(), ^{
            weakSelf.imageView.image = image;
        });
    }];
    [task resume];

使用AFNetWorking下载图片

导入头文件#import “UIImageView+AFNetworking.h”使用:[imageView setImageWithURL:url];UIImageView+AFNetworking做了内存缓存,和基于NSURLSession的网络请求缓存

代码分析:

if ([urlRequest URL] == nil) {
        [self cancelImageDownloadTask];
        self.image = placeholderImage;
        return;
    }
//如果新传入的URL为空则取消图片下载并设置图片为默认图
if ([self isActiveTaskURLEqualToURLRequest:urlRequest]){
        return;
    }
//如果新传入的URL与当前URL相同则直接返回,否则取消当前下载,重新进行图片查找下载
UIImage *cachedImage = [imageCache imageforRequest:urlRequest withAdditionalIdentifier:nil];
//从内存缓存中读取image,如果没有则发起新的请求
AFImageDownloader *downloader = [[self class] sharedImageDownloader];
//使用单例下载,内存缓存为downloader.imageCache
//downloader设置的网络请求20M的内存缓存和150M的硬盘缓存
//downloader设置的网络请求缓存策略为NSURLRequestUseProtocolCachePolicy
//imageCache设置了内存60M最大100M
//网络请求发起前会再次判断imageCache中是否含有该image

测试

使用Charles查看图片下载的网络请求发生了几次,判断缓存是否成功。其中硬盘缓存需要写入时间,网络请求完成后略等一下,否则硬盘缓存不会生效

设置默认网络缓存大小

如果没有对NSURLRequest的URLCache进行设置,默认是使用[NSURLCache sharedURLCache],所以如果有需要可以如下设置

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    [AFNetworkActivityIndicatorManager sharedManager].enabled = YES;
    //网络请求时状态栏网络状态小转轮

    NSURLCache *URLCache = [[NSURLCache alloc] initWithMemoryCapacity:4 * 1024 * 1024
                                                         diskCapacity:20 * 1024 * 1024
                                                             diskPath:nil];
    //内存4M,硬盘20M
    [NSURLCache setSharedURLCache:URLCache];

    return YES;
}

iOS开发--基于AFNetWorking3.0的图片缓存分析的更多相关文章

  1. 【转载】基于AFNetWorking3.0的图片缓存分析

    原文出处: Yasin的简书 理论 不喜欢理论的可以直接跳到下面的Demo实践部分 缓存介绍 缓存按照保存位置可以分为两类:内存缓存.硬盘缓存(FMDB.CoreData…).我们常说的网络请求缓存包 ...

  2. 基于AFNetworking3.0网络封装

    概述 对于开发人员来说,学习网络层知识是必备的,任何一款App的开发,都需要到网络请求接口.很多朋友都还在使用原生的NSURLConnection一行一行地写,代码到处是,这样维护起来更困难了. 对于 ...

  3. iOS_SN_基于AFNetworking3.0网络封装

    转发文章,原地址:http://www.henishuo.com/base-on-afnetworking3-0-wrapper/?utm_source=tuicool&utm_medium= ...

  4. iOS开发系列--无限循环的图片浏览器

    --UIKit之UIScrollView 概述 UIKit框架中有大量的控件供开发者使用,在iOS开发中不仅可以直接使用这些控件还可以在这些控件的基础上进行扩展打造自己的控件.在这个系列中如果每个控件 ...

  5. 【iOS开发】关于显示一连串图片组成动画效果UIImageView的使用

    关于使用UIImageView显示一串图片组成动画效果的总结: 1>创建装这一串图片的容器,使用NSArray NSMutableArray *images = [NSMutableArray ...

  6. IOS开发-基于WebDriverAgent代理服务,实现iOS手机app自动化测试的框架搭建

    导引 iOS自动化测试一直使用的appium,iOS系统升级至10.0 Xcode8.0之后,改用WebDriverAgent代理服务作为server,编写了一套基于WebDriverAgent服务 ...

  7. iOS开发之虾米音乐频道选择切换效果分析与实现

    今天博客的内容比较简单,就是看一下虾米音乐首页中频道选择的一个动画效果的实现.之前用mask写过另外一种Tab切换的一种效果,网易云音乐里边的一种Tab切换效果,详情请移步于"视错觉:从一个 ...

  8. iOS开发项目实战——Swift实现图片轮播与浏览

    近期開始开发一个新的iOS应用,自己决定使用Swift.进行了几天之后,发现了一个非常严峻的问题.那就是无论是书籍,还是网络资源,关于Swift的实在是太少了,随便一搜全都是OC实现某某某功能.就算是 ...

  9. iOS开发笔记--使用blend改变图片颜色

    最近对Core Animation和Core Graphics的内容东西比较感兴趣,自己之前也在这块相对薄弱,趁此机会也想补习一下这块的内容,所以之后几篇可能都会是对CA和CG学习的记录的文章. 在应 ...

随机推荐

  1. WPF的路由事件、冒泡事件、隧道事件(预览事件)

    本文摘要: 1:什么是路由事件: 2:中断事件路由: 3:自定义路由事件: 4:为什么需要自定义路由事件: 5:什么是冒泡事件和预览事件(隧道事件): 1:什么是路由事件 WPF中的事件为路由事件,所 ...

  2. 让Windows2008R2也能进入手柄设置(游戏控制器设置)

    在Windows2008 R2系统中,插入XB360手柄后能自动完成驱动安装,在[设备和打印机]中也会出现手柄,但在上面右键→游戏控制器设置却没反应,什么都没打开,虽然不影响实际游戏,但总感觉有点堵. ...

  3. innobackupex 单脚本循环7天一全备6增备脚本更新

    #!/bin/bash #日期转为天数 function date2days { echo "$*" | awk '{ z=-$)/); y=$+-z; m=$+*z-; j=*m ...

  4. operator= 复制操作符的意外

    首先,看以下的代码的输出时什么: 上述代码做了最理所当然的事.就是将Derived的两个对象进行了交换.可是通过指针进行的赋值输出却不是预期的: 居然调用的是Base的operator=,也就意味着我 ...

  5. MySQL日志Undo&Redo

    00 – Undo LogUndo Log 是为了实现事务的原子性,在MySQL数据库InnoDB存储引擎中,还用Undo Log来实现多版本并发控制(简称:MVCC). - 事务的原子性(Atomi ...

  6. 关于下载SAE日志签名认证的方法——PHP版

    之前需要下载SAE上的日志存入数据库,因此研究了下SAE的签名认证和日志下载.这个链接是SAE官方给出的API文档.https://www.sinacloud.com/doc/api.html#qia ...

  7. 数据结构java(一)数组链表

    链表是数据结构中最基础的内容,链表在存储结构上分成两种:数组形式储存,链式存储. 相比c语言需要的结构体,在java中由于有了面向对象编程,将指针‘藏’了起来,不需要分配内存. 所以只需要创建一个对象 ...

  8. 关于HTMl CSS

    HTML  结构       CSS   表现         JS  行为 首先说一个SEO,搜索引擎优化 标准文档流:(1)前提:在没有css的干预下     (2)块级元素:独占一行,可定义宽和 ...

  9. Perl正则表达式超详细教程

    前言 想必学习perl的人,对基础正则表达式都已经熟悉,所以学习perl正则会很轻松.这里我不打算解释基础正则的内容,而是直接介绍基础正则中不具备的但perl支持的功能.关于基础正则表达式的内容,可参 ...

  10. java----自动类型转换