YYWebImage源码分析
2018-03-08 本文已影响5人
踏云小子
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图片,则是边拿到数据边渲染