前言:
首先,我们要弄明白一个问题? 为什么要对UIImage进行解码呢?难道不能直接使用吗?
其实不解码也是可以使用的,假如说我们通过imageNamed:来加载image,系统默认会在主线程立即进行图片的解码工作。这一过程就是把image解码成可供控件直接使用的位图。
当在主线程调用了大量的imageNamed:方法后,就会产生卡顿了。为了解决这个问题我们有两种比较简单的处理方法:
我们不使用imageNamed:加载图片,使用其他的方法,比如imageWithContentsOfFile:
我们自己解码图片,可以把这个解码过程放到子线程
图片格式
https://www.objccn.io/issue-21-2/
关于 decodedImageWithImage 方法
在我们使用 UIImage 的时候,创建的图片通常不会直接加载到内存,而是在渲染的时候再进行解压并加载到内存。这就会导致 UIImage 在渲染的时候效率上不是那么高效。为了提高效率通过 decodedImageWithImage 方法把图片提前解压加载到内存,这样这张新图片就不再需要重复解压了,提高了渲染效率。这是一种空间换时间的做法。
一般下载或者从磁盘获取的图片是PNG或者JPG,这是经过编码压缩后的图片数据,不是位图,要把它们渲染到屏幕前就需要进行解码转成位图数据,而这个解码操作比较耗时,iOS默认是在主线程解码,所以SDWebImage将这个过程放到子线程了。
同时因为位图体积很大,所以磁盘缓存不会直接缓存位图数据,而是编码压缩后的PNG或JPG数据。
从网络下载的图片,对图片处理的代码:
//从网络获取的图片,不是位图的格式,需要解码成位图的格式
image = [UIImage decodedImageWithImage:image];
网络图片下载完毕,回调的代码
[self.imageCache storeImage:downloadedImage imageData:downloadedData forKey:key toDisk:cacheOnDisk completion:nil];
主要有两大功能:
//1.将位图的图片数据存放到内存缓存中
//2.同时因为位图体积很大,所以磁盘缓存不会直接缓存位图数据,而是编码压缩后的PNG或JPG数据。
- (void)storeImage:(nullable UIImage *)image
imageData:(nullable NSData *)imageData
forKey:(nullable NSString *)key
toDisk:(BOOL)toDisk
completion:(nullable SDWebImageNoParamsBlock)completionBlock {
if (!image || !key) {
if (completionBlock) {
completionBlock();
}
return;
}
// if memory cache is enabled
if (self.config.shouldCacheImagesInMemory) {
//将位图的图片数据存放到内存缓存中
NSUInteger cost = SDCacheCostForImage(image);
[self.memCache setObject:image forKey:key cost:cost];
}
if (toDisk) {
dispatch_async(self.ioQueue, ^{
@autoreleasepool {
NSData *data = imageData;
if (!data && image) {
SDImageFormat imageFormatFromData = [NSData sd_imageFormatForImageData:data];
data = [image sd_imageDataAsFormat:imageFormatFromData];
}
[self storeImageDataToDisk:data forKey:key];
}
if (completionBlock) {
dispatch_async(dispatch_get_main_queue(), ^{
completionBlock();
});
}
});
} else {
if (completionBlock) {
completionBlock();
}
}
}
网友评论