iOS三方库学习
2023-09-01 » 自我成长SDWebImageView
流程图
- sd_setImageWithURL
- sd_internalSetImageWithURL
- loadImageWithURL
- queryCacheOperationForKey
- downloadImageWithURL
- storeImage
- loadImageWithURL
- sd_internalSetImageWithURL
类结构
- SDWebImageDownloader
- SDWebImageDownloaderConfig (下载配置)
- SDWebImageDownloaderOptions (下载规则)
- SDWebImageDownloaderRequestModifier (外部可配置,检查修改URLRequest,在请求之前生效)
- SDWebImageDownloaderResponseModifier (外部可配置,检查修改URLResponse,请求回来之后调用)
- SDWebImageDownloaderDecryptor (请求回来之后解密用)
- SDImageLoadersManager
- SDImageLoader(protocol)
- 方法 canRequestImageForURL
- 方法 requestImageWithURL
- SDImageLoader(protocol)
- SDWebImageDownloadToken (关联每一个下载的token)
- SDWebImageOperation (protocol + NSOperation扩展)
- cancel (取消任务)
- SDWebImageOperation (protocol + NSOperation扩展)
- 网络下载 downloadImageWithURL
- 核心类
- protocol SDWebImageDownloaderOperation <NSURLSessionTaskDelegate, NSURLSessionDataDelegate>
- SDWebImageDownloaderOperation : NSOperation
- NSMutableArray<SDWebImageDownloaderOperationToken *> *callbackTokens
- 判断是否有缓存 NSMutableDictionary<NSURL *, NSOperation
*> *URLOperations - 有缓存但是已经完结或者被取消、无缓存,重新构建新的operation
- 创建NSMutableURLRequest对象,设置缓存策略、是否使用默认Cookies 、Http头信息等
- 检查是否有外部的配置(请求修改器、响应修改器、解码器、网络请求证书)
- 返回SDWebImageDownloadToken对象,该对象包含了url、request、以及downloadOperationCancelToken
- 外部可以根据token进行任务取消
- 创建NSMutableURLRequest对象,设置缓存策略、是否使用默认Cookies 、Http头信息等
-
有缓存且可用,将该方法传入的progressBlock和completedBlock加入到operation中,同时若该operation还未被执行时,会根据传入的options调整当前queue的优先级
- 有缓存但是已经完结或者被取消、无缓存,重新构建新的operation
- 核心类
图片下载
SDWebImageDownloader单例对象
- 每个请求创建SDWebImageDownloadToken管理下载实例
- SDWebImageDownloader保存每个下载任务方便取消
- SDWebImageDownloadToken包含SWDweImageDownloaderOperation用于实际下载逻辑
- SDWebImageDownloaderOperationToken 管理单个下载,包括取消
NSOperation 队列
SDWebImageDownloaderOperation子类,SDWebImageDownloaderOperation协议<NSURLSessionTaskDelegate, NSURLSessionDataDelegate>
SDWebImageDownloaderOperation 下面还有 SDWebImageDownloaderOperationToken 可以操作取消
NSURLCache、NSCache
- 优势
-
支持内存、硬盘上的缓存,无需管理缓存,只需设置缓存上限 会自动清理
- 劣势
- 可自定义空间小,使用的都是NSData,每次都需要重新转换
SDImageCache 两级缓存
- 1、SDMemoryCache
本身继承自NSCache,会跟进系统内存紧张程度自行释放部分缓存
本身内部又开了一个弱缓存,NSMapTable
我的理解是为了提高缓存命中率,当系统内存紧张的时候NSCache自动在释放, 可能释放了当前在用的某些图片资源,这个时候如果这部分资源再次搜索缓存可能就会找不到,需要读磁盘,这个时候弱缓存可以命中,命中后再往NSCache中塞一份
通过重写setObject来实现 弱缓存的处理
最新版本用的不是自旋锁 是不公平锁(互斥锁)
#define SD_LOCK_DECLARE(lock) os_unfair_lock lock
- 2、diskCache
IO 操作队列 是一个串行队列
_ioQueue = dispatch_queue_create(“com.hackemist.SDImageCache.ioQueue”, DISPATCH_QUEUE_SERIAL)
- 图片类型分解,encode成NSData,串行队列异步写入diskcache
- 检查图片是否有sd_extendedObject,如果有则也会存储到硬盘中,使用了NSKeyedArchiver将sd_extendedObject转换为NSData,同上 一并写入diskcach
缓存的查找
SDImageCacheToken 处理diskCache查找操作,可以按key cancle
缓存的清理
1、根据配置,设置选择文件的访问时间,是以何种策略来淘汰文件,是根据创建时间超时,还是内容修改时间超时等依据 LRU
case SDImageCacheConfigExpireTypeAccessDate:
case SDImageCacheConfigExpireTypeModificationDate:
case SDImageCacheConfigExpireTypeCreationDate:
case SDImageCacheConfigExpireTypeChangeDate:
2、删完过期的 删除超出大小的 直到小于预设值( 如果当前磁盘存储文件的总大小大于配置的大小) const NSUInteger desiredCacheSize = maxDiskSize / 2;
3、删除时机,申请系统后台时间处理任务
iOS的后台任务有个背景,不管任何时候,都需要手动去调用endBackgroundTask结束后台任务,其实开启一个后台job的时候,因为时长有限,所以会存在两种结局:
1、在允许的时间内执行完成 2、规定时间内未执行完成 如上两种情况,在结束后都必须手动调用endBackgroundTask
- applicationWillTerminate
dispatch_sync(self.ioQueue, ^{ [self.diskCache removeExpiredData]; });
- applicationDidEnterBackground
[self deleteOldFilesWithCompletionBlock:^{ [application endBackgroundTask:bgTask]; bgTask = UIBackgroundTaskInvalid; }];
图片解码
https://www.jianshu.com/p/49ba11db96c6
SDImageCoder 工厂模式的coder SDImageCoder 协议
解码操作在@autoreleasepool中,可以使得局部变量能尽早释放掉,避免内存峰值过高
1、普通解码
decodedImageWithImage
2、处理大图缩放和解码 (60M+) decodedAndScaledDownImageWithImage
使用分块绘制的方式,读取一部分图片的data绘制成图,再把图绘制到缩放过的 context 中,然后释放掉之前读取的 data。循环往复,将整张图都绘制出来。这样能够解决内存爆炸问题
3、downsampleImage 下采样
原理:缩略图策略,就是把 S * S区域内的图像变成一个像素点
动图处理
2、动图播放原理
SDAnimatedImagePlayer
- SDDisplayLink + SDWeakProxy 刷新动画
- displayLayer 一帧一帧刷在imageView的layer上 (同时预加载下一帧)
其他图片优化策略
上采样 放大图,下采样 缩小图
图片的下载策略,网络这部分
https://www.jianshu.com/p/f15ad28ce3d1
AFNetworking
网络请求
请求缓慢检测
对发送请求/DNS查询/TLS握手/请求响应等各种环节时间上的指标统计。 更易于我们检测, 分析我们App的请求缓慢到底是发生在哪个环节, 并对此进行优化提升我们APP的性能。
NSURLSessionTaskMetrics对象与NSURLSessionTask对象一一对应. 每个NSURLSessionTaskMetrics对象内有3个属性 :
- taskInterval : task从开始到结束总共用的时间
- redirectCount : task重定向的次数
- transactionMetrics : 一个task从发出请求到收到数据过程中派生出的每个子请求, 它是一个装着许多NSURLSessionTaskTransactionMetrics对象的数组,每个对象都代表下图的一个子过程。
API很简单, 就一个方法 : - (void)URLSession:task:didFinishCollectingMetrics:, 当收集完成的时候就会调用该方法。
身份验证和自定义TLS
当一个服务器请求身份验证或TLS握手期间需要提供证书的话, URLSession会调用他的代理方法URLSession:didReceiveChallenge:completionHandler:去处理.
如果你没有实现该代理方法, URLSession就会这么做 :
-
使用身份认证信息作为请求URL的一部分(如果可用的话)
-
在用户的keychain中查找网络密码和证书(in macOS), 在app的keychain中查找(in iOS) 如果证书还是不可用或服务器拒绝该证书, 就会继续缺少身份认证的连接.
-
对于HTTP(S)连接, 请求失败并返回一个状态码, 可能会提供一些替代的内容, 例如一个私人网站的公共网页.
- 对于其他URL类型(如FTP等), 则连接请求失败, 直接返回错误信息
- App Transport Security
从iOS9开始支持ATS, 且默认ATS只支持发送HTTPS请求, 不允许发送不安全的HTTP请求. 如果用户需要发送HTTP请求需要在info.plist中配置
客户端验证服务端证书
1、客户端和服务端建立一个连接,服务端返回一个证书,客户端里存有各个受信任的证书机构根证书(CA根证书),用这些根证书对服务端返回的证书进行验证 2、经验证如果证书是可信任的,就生成一个pre-master secret,用这个证书的公钥加密后发送给服务端,服务端用私钥解密后得到pre-master secret,再根据某种算法生成master secret 3、客户端也同样根据这种算法从pre-master secret 生成 master secret,随后双方的通信都用这个 master secret 对传输数据进行加密解密
验证细节: 1、服务端返回证书A给客户端,证书A用CA根证书私钥签名过信息 2、客户端的系统里的CA机构根证书有这个CA机构的公钥,用这个公钥对证书A的加密内容F1解密得到F2,跟证书A里内容F对比,若相等就通过验证
中间人截获服务端发给客户端的证书,但是本身没有私钥,所以客户端公钥加密后的内容 中间人是无法解析的,后续通信过程用的是两端沟通后的同一个对称加密秘钥加密的内容,所以中间人两头都无法解析