YYWebImage源码分析

1. 网络请求下载图片

YY用的是NSURLConnection,这个其实可以用NSURLSession替换

2. 图片解码

2.1 判断图片格式

2.2 不同图片格式对应不同的显示方式

  • JPEG, PNG, GIF都支持逐行显示(baseline)


    image_baseline.gif
  • PNG,GIF支持隔行显示(interlaced)


    image_interlaced.gif
  • 只有JPEG支持渐进式加载


    image_progressive.gif

2.3 如何判断图片格式

取图片数据的第一个字节

//通过图片Data数据第一个字节 来获取图片扩展名
- (NSString *)contentTypeForImageData:(NSData *)data{
    uint8_t c;
    [data getBytes:&c length:1];
    switch (c) {
        case 0xFF:
            return @"jpeg";
        case 0x89:
            return @"png";
        case 0x47:
            return @"gif";
        case 0x49:
        case 0x4D:
            return @"tiff";
        case 0x52:
            if ([data length] < 12) {
                return nil;
            }
            NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding];
            if ([testString hasPrefix:@"RIFF"] && [testString hasSuffix:@"WEBP"]) {
                return @"webp";
            }
            return nil;
    }
    return nil;
}

2.4 图片缓存设置

NSURLRequest 有个 cachePolicy 属性,它根据以下常量指定了请求的缓存行为:

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

如果你需要更精确的缓存策略,NSURLSessionDataDelegate代理里的URLSession:dataTask:willCacheResponse:completionHandler:方法或者NSURLConnection的connection:willCacheResponse:可以实现

2.5 为什么用pthread_mutex_lock对图片原始处理时加锁,怎么使用?

之所以用pthread_mutex_lock是因为dispacth_semaphore无法解决递归调用问题,同时性能上NSRecursiveLock也没有它好,而处理图片二进制数据对性能有一定要求,所以用pthread_mutex_lock
YYWebImage的源码如下

- (instancetype)initWithScale:(CGFloat)scale {
    self = [super init];
    if (scale <= 0) scale = 1;
    _scale = scale;
    _framesLock = dispatch_semaphore_create(1);
    
    pthread_mutexattr_t attr;
    pthread_mutexattr_init (&attr);
    pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);//设置锁为递归锁
    pthread_mutex_init (&_lock, &attr);
    pthread_mutexattr_destroy (&attr);
    
    return self;
}
- (BOOL)updateData:(NSData *)data final:(BOOL)final {
    BOOL result = NO;
    pthread_mutex_lock(&_lock);
    result = [self _updateData:data final:final];
    pthread_mutex_unlock(&_lock);
    return result;
}

关于pthread_mutex_lock 的使用详见这里

2.6 PNG图片的解码

对于png,作者是拿到全部数据后再渲染,我之前做过一个边拿数据边渲染的测试,结果很耗资源;而jpeg图片,则是边拿到数据边渲染

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容