iOS三方库学习

2023-09-01 » 自我成长

SDWebImageView

流程图

img

  • sd_setImageWithURL
    • sd_internalSetImageWithURL
      • loadImageWithURL
        • queryCacheOperationForKey
        • downloadImageWithURL
          • storeImage

类结构

  • SDWebImageDownloader
    • SDWebImageDownloaderConfig (下载配置)
    • SDWebImageDownloaderOptions (下载规则)
    • SDWebImageDownloaderRequestModifier (外部可配置,检查修改URLRequest,在请求之前生效)
    • SDWebImageDownloaderResponseModifier (外部可配置,检查修改URLResponse,请求回来之后调用)
    • SDWebImageDownloaderDecryptor (请求回来之后解密用)
    • SDImageLoadersManager
      • SDImageLoader(protocol)
        • 方法 canRequestImageForURL
        • 方法 requestImageWithURL
    • SDWebImageDownloadToken (关联每一个下载的token)
      • SDWebImageOperation (protocol + NSOperation扩展)
        • cancel (取消任务)
    • 网络下载 downloadImageWithURL
      • 核心类
        • protocol SDWebImageDownloaderOperation <NSURLSessionTaskDelegate, NSURLSessionDataDelegate>
        • SDWebImageDownloaderOperation : NSOperation
          • NSMutableArray<SDWebImageDownloaderOperationToken *> *callbackTokens
      • 判断是否有缓存 NSMutableDictionary<NSURL *, NSOperation *> *URLOperations
        • 有缓存但是已经完结或者被取消、无缓存,重新构建新的operation
          • 创建NSMutableURLRequest对象,设置缓存策略、是否使用默认Cookies 、Http头信息等
            • 检查是否有外部的配置(请求修改器、响应修改器、解码器、网络请求证书)
          • 返回SDWebImageDownloadToken对象,该对象包含了url、request、以及downloadOperationCancelToken
          • 外部可以根据token进行任务取消
        • 有缓存且可用,将该方法传入的progressBlock和completedBlock加入到operation中,同时若该operation还未被执行时,会根据传入的options调整当前queue的优先级

图片下载

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对象的数组,每个对象都代表下图的一个子过程。

img

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中配置

NSAppTransportSecurity NSAllowsArbitraryLoads

客户端验证服务端证书

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对比,若相等就通过验证

中间人截获服务端发给客户端的证书,但是本身没有私钥,所以客户端公钥加密后的内容 中间人是无法解析的,后续通信过程用的是两端沟通后的同一个对称加密秘钥加密的内容,所以中间人两头都无法解析