在應(yīng)用SDWebImage過程中,遇到了一些技術(shù)問題和細(xì)節(jié)問題,現(xiàn)在總結(jié)一下,并
進(jìn)行了相關(guān)的技術(shù)擴(kuò)展,SDWebImage確實(shí)是個(gè)值得研究的框架
場景一:當(dāng)我們?cè)谝粋€(gè)頁面中加載特別多的九宮格圖片,那么當(dāng)我們滑動(dòng)頁面肯定會(huì)造成內(nèi)存的暴漲,如何處理那?
首先對(duì)內(nèi)存進(jìn)行監(jiān)聽
//監(jiān)聽內(nèi)存警告
[[NSNotificationCenter defaultCenter]addObserverForName:UIApplicationDidReceiveMemoryWarningNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
NSLog(@"內(nèi)存暴漲");
// 1.取消正在下載的操作
[[SDWebImageManager sharedManager] cancelAll];
// 2.清除內(nèi)存緩存
[[SDWebImageManager sharedManager].imageCache clearWithCacheType:SDImageCacheTypeAll completion:nil];
}];
加載圖片的處理
// SDWebImageLowPriority 當(dāng)UIScrollView滑動(dòng)減速時(shí)開始加載圖片 SDWebImageAvoidDecodeImage由于過多的內(nèi)存消耗,這個(gè)標(biāo)志可以防止解碼圖像。
[self.Pic sd_setImageWithURL:self.url placeholderImage:[UIImage imageNamed:@"logo"] options:SDWebImageLowPriority|SDWebImageAvoidDecodeImage];
場景二:如何讓下載的圖片展示出網(wǎng)頁那種從上到下顯示的效果?
直接設(shè)置SDWebImageProgressiveLoad
[self.image sd_setImageWithURL:self.URL placeholderImage:nil options:SDWebImageProgressiveLoad];

場景三:設(shè)置了SDWebImageRefreshCached,緩存圖片如何更新?
現(xiàn)在提供兩種方法來解決這個(gè)問題 - 舊版本SDWebImage:
首先我們需要探討一下實(shí)現(xiàn)的原理:一種是NSURLCache(NSURL緩存的get請(qǐng)求),一種是SD中自己定義的SDImageCache進(jìn)行緩存。在SDWebImage中我們可以查看SDWebImageRefreshCached是如何定義的 - 如果設(shè)置了該類型,緩存策略依據(jù)NSURLCache而不是SDImageCache,所以可以通過NSURLCache進(jìn)行緩存了;
但是圖片的更新還需要的服務(wù)器的配合才能實(shí)現(xiàn),服務(wù)器如何設(shè)置那?圖片的更新與否取決于你服務(wù)器的cache-control設(shè)置,如果沒有cache-control設(shè)置,那么客戶端就享受不了自動(dòng)更新的功能。首先了解一下cache-control,
終端中輸入命令: curl [url] --head

發(fā)現(xiàn)有Cache-Control,說明是可以的。這其實(shí)就是請(qǐng)求照片的過程中,返回來的header信息,這其中還包括一個(gè)名為Last-Modified、數(shù)據(jù)是時(shí)間戳的鍵值對(duì)。
首先為查看HTTP協(xié)議相關(guān)的資料,發(fā)現(xiàn)request header中有一個(gè)名為if-Modified-Since的key,value就是服務(wù)器返回的服務(wù)器最后被修改的時(shí)間;第一次請(qǐng)求過程中由于并沒有攜帶該request header所以if-Modified-Since為空,第一次請(qǐng)求成功之后,將返回的Last-Modified值做為if-Modified-Since的值傳回給服務(wù)器。這樣后臺(tái)就會(huì)對(duì)if-Modified-Since和Last-Modified進(jìn)行比較,如果客戶端圖片已經(jīng)過期,那么返回狀態(tài)碼200、Last-modified和圖片內(nèi)容,客戶端重新將Last-modified存儲(chǔ)到if-Modified-Since;如果客戶端返回的是304 not Modified、則不會(huì)返回last-Modified、圖片內(nèi)容,說明圖片沒有更新,直接拿緩存中數(shù)據(jù)就行。
回到SDWebImage上,通過查看老的SDWebImageDownloader版本代碼發(fā)現(xiàn),它開放了一個(gè)headersFilter的block,我們可以在這個(gè)block中追加額外的header,所以我們可以在例如AppDelegate didFinishLaunching的地方追加如下代碼:
SDWebImageDownloader *imgDownloader = SDWebImageManager.sharedManager.imageDownloader;
imgDownloader.headersFilter = ^NSDictionary *(NSURL *url, NSDictionary *headers) {
NSFileManager *fm = [[NSFileManager alloc] init];
NSString *imgKey = [SDWebImageManager.sharedManager cacheKeyForURL:url];
NSString *imgPath = [SDWebImageManager.sharedManager.imageCache defaultCachePathForKey:imgKey];
NSDictionary *fileAttr = [fm attributesOfItemAtPath:imgPath error:nil];
NSMutableDictionary *mutableHeaders = [headers mutableCopy];
NSDate *lastModifiedDate = nil;
if (fileAttr.count > 0) {
if (fileAttr.count > 0) {
lastModifiedDate = (NSDate *)fileAttr[NSFileModificationDate];
}
}
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];
formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
formatter.dateFormat = @"EEE, dd MMM yyyy HH:mm:ss z";
NSString *lastModifiedStr = [formatter stringFromDate:lastModifiedDate];
lastModifiedStr = lastModifiedStr.length > 0 ? lastModifiedStr : @"";
[mutableHeaders setValue:lastModifiedStr forKey:@"If-Modified-Since"];
return mutableHeaders;
復(fù)制代碼
};
SDWebImage
然后加載圖片的地方之前怎么寫就怎么寫,但是option中一定要加上SDWebImageRefreshCached
另外一種方法:
在SDWebImageManager.m大約167行的地方加上
// remove SDWebImageDownloaderUseNSURLCache flag downloaderOptions &= ~SDWebImageDownloaderUseNSURLCache;
變成了
if (cachedImage && options & SDWebImageRefreshCached) {
// force progressive off if image already cached but forced refreshing
downloaderOptions &= ~SDWebImageDownloaderProgressiveDownload;
// remove SDWebImageDownloaderUseNSURLCache flag
downloaderOptions &= ~SDWebImageDownloaderUseNSURLCache;
// ignore image read from NSURLCache if image if cached but force refreshing
downloaderOptions |= SDWebImageDownloaderIgnoreCachedResponse;
}
注意:最新版本中已經(jīng)解決了這個(gè)問題
在之前的版本中,如果服務(wù)端更新了圖片,雖然設(shè)置了SDWebImageRefreshCached,還是拿到的老圖片,在最新版5.1.0中已經(jīng)解決了這個(gè)問題 - 應(yīng)用的SDImageCache,通過每次圖片的重新網(wǎng)絡(luò)請(qǐng)求,和當(dāng)前的緩存數(shù)據(jù)做比較,如果不同那么就將新請(qǐng)求到的image通過block返回。
//判斷是否更新了,包括SDWebImageDownloaderIgnoreCachedResponse/本地緩存對(duì)比
if (self.options & SDWebImageDownloaderIgnoreCachedResponse && [self.cachedData isEqualToData:imageData]) {
//如果和本地緩存相同,那么返回SDWebImageErrorCacheNotModified
self.responseError = [NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorCacheNotModified userInfo:nil];
// call completion block with not modified error
[self callCompletionBlocksWithError:self.responseError];
[self done];
//如果沒有更新,那么在子線程進(jìn)圖片處理
} else {
// decode the image in coder queue
dispatch_async(self.coderQueue, ^{
@autoreleasepool {
另外也可以應(yīng)用Cache-control,但是最新版的并沒有暴露headersFilter,而是暴露了
/**
* Set a value for a HTTP header to be appended to each download HTTP request.
*
* @param value The value for the header field. Use `nil` value to remove the header field.
* @param field The name of the header field to set.
*/
- (void)setValue:(nullable NSString *)value forHTTPHeaderField:(nullable NSString *)field;
[[SDWebImageDownloader sharedDownloader] setValue:@"" forHTTPHeaderField:@""];
通過這個(gè)方法,我們可以將if-Modified-Since 傳入SDWebImageDownloader即可,同樣還是需要在option中傳入SDWebImageRefreshCached
場景四:圖片的解壓縮問題?
設(shè)置SDWebImageAvoidDecodeImage,這個(gè)option到底是如何實(shí)現(xiàn)在子線程解壓縮圖片的那?
圖片的加載工作流
將一張圖片從磁盤加載到內(nèi)存然后渲染到屏幕上,這個(gè)過程的消耗其實(shí)非常的大,會(huì)明顯降低界面的幀速率,當(dāng)滾動(dòng)的時(shí)候會(huì)加劇這一情況,因?yàn)閮?nèi)容變化的太快,需要更快的處理速度才能保持在60FPS的幀速率。
首先考慮一下加載的工作流程:
- [UIImage imageWithContentsOfFile:]使用Image I/O創(chuàng)建CGImageRef內(nèi)存映射數(shù)據(jù)。此時(shí),圖像尚未解碼。
- 返回的數(shù)據(jù)被返回給UIImageView。
- 隱式CATransaction捕獲這些層樹修改。
- 在主運(yùn)行循環(huán)的下一次迭代中,Core Animation提交隱式事物,這可能涉及創(chuàng)建已設(shè)置為層內(nèi)容的任何圖像的副本。根據(jù)圖像,復(fù)制它涉及一下部分或全部步驟:
- 緩沖區(qū)被分配用于管理文件和解壓縮操作
- 文件數(shù)據(jù)從磁盤讀入內(nèi)存
- 壓縮的圖像數(shù)據(jù)被解壓縮成其未壓縮的位圖形式,這通常是CPU密集型操作
- 然后Core Animation使用未壓縮的位圖數(shù)據(jù)來渲染涂層
擴(kuò)展:Core Animation不僅能用來做動(dòng)畫,實(shí)際上是一個(gè)叫做Layer kit這么一個(gè)不怎么和動(dòng)畫相關(guān)的名字演變來的。Core Animation其實(shí)是一個(gè)復(fù)合引擎,它的指責(zé)是盡快的組合屏幕上不同的可視內(nèi)容,這個(gè)內(nèi)容是被分解成獨(dú)立的涂層,存儲(chǔ)在一個(gè)叫圖層樹的體系之中,這個(gè)樹形成了UIKit以及在iOS程序中你能在屏幕上看到的一切的基礎(chǔ)。
時(shí)鐘信號(hào):垂直同步信號(hào)V-Sync/水平同步信號(hào)H-Sync,有這兩個(gè)信號(hào)來按照信號(hào)時(shí)間,定時(shí)進(jìn)行界面的相應(yīng)展示
CPU:計(jì)算視圖frame,圖片的解壓縮
GPU:紋理繪制,頂點(diǎn)變換,像素點(diǎn)的填充,渲染
當(dāng)圖片過大那么CPU解壓就會(huì)非常耗時(shí),那么在當(dāng)前的水平同步信號(hào)到來到結(jié)束這一段時(shí)間內(nèi),如果沒有解壓或者渲染完成,那么到下一個(gè)H-Sync信號(hào)到來時(shí)就會(huì)出現(xiàn)拖尾現(xiàn)象 - 卡頓。
位圖
如果不進(jìn)行解壓縮,直接渲染是不行的,必須要解壓成位圖,那么什么是位圖那?
UIImage *image = [UIImage imageNamed:@"logo.png"];
CFDataRef mapData = CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage));
通過CGDataProviderCopyData獲取到的mapData就是位圖,可以嘗試打印,
發(fā)現(xiàn)位圖其實(shí)就是一個(gè)像素?cái)?shù)組,有一個(gè)獲取圖片解壓后位圖大小的公式
圖片像素寬 圖片像素高4 = 位圖大小
事實(shí)上,不管是 JPEG 還是 PNG 圖片,都是一種壓縮的位圖圖形格式。只不過 PNG 圖片是無損壓縮,并且支持 alpha 通道,而 JPEG 圖片則是有損壓縮,可以指定 0-100% 的壓縮比。值得一提的是,在蘋果的 SDK 中專門提供了兩個(gè)函數(shù)用來生成 PNG 和 JPEG 圖片:
// return image as PNG. May return nil if image has no CGImageRef or invalid bitmap format
UIKIT_EXTERN NSData * __nullable UIImagePNGRepresentation(UIImage * __nonnull image);
// return image as JPEG. May return nil if image has no CGImageRef or invalid bitmap format. compression is 0(most)..1(least)
UIKIT_EXTERN NSData * __nullable UIImageJPEGRepresentation(UIImage * __nonnull image, CGFloat compressionQuality);
所以其實(shí)我們平時(shí)的PNG/JPEG,都是壓縮之后的圖片,需要對(duì)圖片進(jìn)行解壓獲取圖片的位圖進(jìn)行渲染。
解壓縮API
默認(rèn)情況下SDWebImage獲取到圖片的壓縮文件之后,需要用戶在UIImageView賦值的同時(shí)進(jìn)行解壓縮,但是在SDWebImage中如果設(shè)置了SDWebImageAvoidDecodeImage,根本原理是在子線程解壓成位圖,并進(jìn)行繪制。用到的主要API就是CGBitmapContextCreate:,
CG_EXTERN CGContextRef __nullable CGBitmapContextCreate(void * __nullable data,
size_t width, size_t height, size_t bitsPerComponent, size_t bytesPerRow,
CGColorSpaceRef cg_nullable space, uint32_t bitmapInfo)
CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
這個(gè)函數(shù)就是繪制一個(gè)位圖上下文。
data :如果不為 NULL ,那么它應(yīng)該指向一塊大小至少為 bytesPerRow * height 字節(jié)的內(nèi)存;如果 為 NULL ,那么系統(tǒng)就會(huì)為我們自動(dòng)分配和釋放所需的內(nèi)存,所以一般指定 NULL 即可;
width 和height :位圖的寬度和高度,分別賦值為圖片的像素寬度和像素高度即可;
bitsPerComponent :像素的每個(gè)顏色分量使用的 bit 數(shù),在 RGB 顏色空間下指定 8 即可;
bytesPerRow :位圖的每一行使用的字節(jié)數(shù),大小至少為 width * bytes per pixel 字節(jié)。當(dāng)我們指定 0/NULL 時(shí),系統(tǒng)不僅會(huì)為我們自動(dòng)計(jì)算,而且還會(huì)進(jìn)行 cache line alignment 的優(yōu)化
space :就是我們前面提到的顏色空間,一般使用 RGB 即可;
bitmapInfo :位圖的布局信息,alpha/顏色分量是否是浮點(diǎn)數(shù)/像素格式的字節(jié)順序。如果有alpha那么用kCGImageAlphaPremultipliedFirst,否則用kCGImageAlphaNoneSkipFirst。像素格式(大端小端/16或者32未)使用kCGBitmapByteOrder32Host(關(guān)于布局信息的更多信息)
查看SDWebImage中的解壓
首先獲得圖片是否有alpha
//判斷是否有alpha
+ (BOOL)CGImageContainsAlpha:(CGImageRef)cgImage {
if (!cgImage) {
return NO;
}
//獲取圖片的alpha信息
CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(cgImage);
//kCGImageAlphaNone沒有alpha
//kCGImageAlphaNoneSkipFirst在RGB透明通道下,alpha沒有在最高有效位
//kCGImageAlphaNoneSkipLast在RGB透明通道下,alpha沒有在最低有效位
//這三者都得包括
BOOL hasAlpha = !(alphaInfo == kCGImageAlphaNone ||
alphaInfo == kCGImageAlphaNoneSkipFirst ||
alphaInfo == kCGImageAlphaNoneSkipLast);
return hasAlpha;
}
然后根據(jù)Bitmap構(gòu)造上下文函數(shù)生成bitmap上下文,并對(duì)圖片進(jìn)行transform,獲取圖片上下文
+ (CGImageRef)CGImageCreateDecoded:(CGImageRef)cgImage orientation:(CGImagePropertyOrientation)orientation {
if (!cgImage) {
return NULL;
}
//獲取圖片的像素寬高
size_t width = CGImageGetWidth(cgImage);
size_t height = CGImageGetHeight(cgImage);
if (width == 0 || height == 0) return NULL;
size_t newWidth;
size_t newHeight;
//查看當(dāng)前圖片的展示方式是否正確,對(duì)width/height進(jìn)行調(diào)整
switch (orientation) {
case kCGImagePropertyOrientationLeft:
case kCGImagePropertyOrientationLeftMirrored:
case kCGImagePropertyOrientationRight:
case kCGImagePropertyOrientationRightMirrored: {
//kCGImagePropertyOrientationRightMirrored這種情況應(yīng)該交換寬高
newWidth = height;
newHeight = width;
}
break;
default: {
//否則不需要處理
newWidth = width;
newHeight = height;
}
break;
}
//是否有alpha通道
BOOL hasAlpha = [self CGImageContainsAlpha:cgImage];
//像素格式中的字節(jié)順序是系統(tǒng)提供的32位主機(jī)字節(jié)順序
CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host;
//將像素格式中用位域技術(shù)添加alpha信息
bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst;
//獲得位圖的上下文
//默認(rèn)的顏色空間是CGColorSpaceCreateDeviceRGB()
//bytesPerRow 每一行的位圖大小設(shè)置為0,系統(tǒng)進(jìn)行自動(dòng)計(jì)算并且進(jìn)行優(yōu)化
//每一個(gè)像素的顏色分量bit數(shù)是8
CGContextRef context = CGBitmapContextCreate(NULL, newWidth, newHeight, 8, 0, [self colorSpaceGetDeviceRGB], bitmapInfo);
if (!context) {
return NULL;
}
//圖片進(jìn)行反轉(zhuǎn),保證展示出來的是沒有transform的圖片
CGAffineTransform transform = SDCGContextTransformFromOrientation(orientation, CGSizeMake(newWidth, newHeight));
CGContextConcatCTM(context, transform);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), cgImage); // The rect is bounding box of CGImage, don't swap width & height
//獲得當(dāng)前上下文中的位圖對(duì)應(yīng)的圖片
CGImageRef newImageRef = CGBitmapContextCreateImage(context);
CGContextRelease(context);
return newImageRef;
}
這就是整個(gè)的圖片在自線程利用CGBitmapContextCreate進(jìn)行解壓縮的過程
場景五:SD中核心方法中context使用問題?
/**
* 通過URL加載圖片,如果cache中存在就從cache中獲取,否則開始下載
*
* @param url 傳入的image的url
* @param options 獲取圖片的方式
* @param context 獲取
* @param progressBlock 獲得圖片的進(jìn)度(注意是在子隊(duì)列中)
* @param completedBlock 完成獲取之后的回掉block
* @return 返回一個(gè)SDWebImageCombinedOperation對(duì)象,用于表示當(dāng)前的圖片獲取任務(wù),在這個(gè)對(duì)象中可以取消獲取圖片任務(wù)
*/
- (nullable SDWebImageCombinedOperation *)loadImageWithURL:(nullable NSURL *)url
options:(SDWebImageOptions)options
context:(nullable SDWebImageContext *)context
progress:(nullable SDImageLoaderProgressBlock)progressBlock
completed:(nonnull SDInternalCompletionBlock)completedBlock;
其中context中對(duì)應(yīng)了很多的業(yè)務(wù)場景,我們可以自己定義
(1). SDWebImageContextImageTransformer - 處理加載出來的圖片,比如翻轉(zhuǎn)圓角等
(2). SDWebImageContextCacheKeyFilter - 指定圖片的緩存key
(3). SDWebImageContextCacheSerializer - 轉(zhuǎn)換需要緩存的圖片格式
(1)、SDWebImageContextImageTransformer 其對(duì)應(yīng)的是遵守SDImageTransformer協(xié)議的類,查看系統(tǒng)方法可以找到具體的圖片處理類型:
@protocol SDImageTransformer <NSObject>
@required
/**
@return 在原始緩存中最后添加的自定義cache key
*/
@property (nonatomic, copy, readonly, nonnull) NSString *transformerKey;
/**
調(diào)用當(dāng)前方法實(shí)現(xiàn)圖片的處理
@param image 處理之后的圖片
@param key 原始圖片關(guān)聯(lián)的cache key
@return 處理之后的圖片
*/
- (nullable UIImage *)transformedImageWithImage:(nonnull UIImage *)image forKey:(nonnull NSString *)key;
@end
#pragma mark - Pipeline
/**
//可以傳入一個(gè)NSArray<SDImageTransformer>數(shù)組,按順序做轉(zhuǎn)換
*/
@interface SDImagePipelineTransformer : NSObject <SDImageTransformer>
/**
*/
@property (nonatomic, copy, readonly, nonnull) NSArray<id<SDImageTransformer>> *transformers;
- (nonnull instancetype)init NS_UNAVAILABLE;
+ (nonnull instancetype)transformerWithTransformers:(nonnull NSArray<id<SDImageTransformer>> *)transformers;
@end
/**
添加圓角
*/
@interface SDImageRoundCornerTransformer: NSObject <SDImageTransformer>
@property (nonatomic, assign, readonly) CGFloat cornerRadius;
@property (nonatomic, assign, readonly) SDRectCorner corners;
@property (nonatomic, assign, readonly) CGFloat borderWidth;
@property (nonatomic, strong, readonly, nullable) UIColor *borderColor;
- (nonnull instancetype)init NS_UNAVAILABLE;
+ (nonnull instancetype)transformerWithRadius:(CGFloat)cornerRadius corners:(SDRectCorner)corners borderWidth:(CGFloat)borderWidth borderColor:(nullable UIColor *)borderColor;
@end
/**
調(diào)整大小
*/
@interface SDImageResizingTransformer : NSObject <SDImageTransformer>
@property (nonatomic, assign, readonly) CGSize size;
@property (nonatomic, assign, readonly) SDImageScaleMode scaleMode;
- (nonnull instancetype)init NS_UNAVAILABLE;
+ (nonnull instancetype)transformerWithSize:(CGSize)size scaleMode:(SDImageScaleMode)scaleMode;
@end
/**
裁剪
*/
@interface SDImageCroppingTransformer : NSObject <SDImageTransformer>
@property (nonatomic, assign, readonly) CGRect rect;
- (nonnull instancetype)init NS_UNAVAILABLE;
+ (nonnull instancetype)transformerWithRect:(CGRect)rect;
@end
/**
翻轉(zhuǎn)
*/
@interface SDImageFlippingTransformer : NSObject <SDImageTransformer>
@property (nonatomic, assign, readonly) BOOL horizontal;
@property (nonatomic, assign, readonly) BOOL vertical;
- (nonnull instancetype)init NS_UNAVAILABLE;
+ (nonnull instancetype)transformerWithHorizontal:(BOOL)horizontal vertical:(BOOL)vertical;
@end
/**
旋轉(zhuǎn)
*/
@interface SDImageRotationTransformer : NSObject <SDImageTransformer>
@property (nonatomic, assign, readonly) CGFloat angle;
@property (nonatomic, assign, readonly) BOOL fitSize;
- (nonnull instancetype)init NS_UNAVAILABLE;
+ (nonnull instancetype)transformerWithAngle:(CGFloat)angle fitSize:(BOOL)fitSize;
@end
#pragma mark - Image Blending
/**
添加色彩
*/
@interface SDImageTintTransformer : NSObject <SDImageTransformer>
@property (nonatomic, strong, readonly, nonnull) UIColor *tintColor;
- (nonnull instancetype)init NS_UNAVAILABLE;
+ (nonnull instancetype)transformerWithColor:(nonnull UIColor *)tintColor;
@end
#pragma mark - Image Effect
/**
添加模糊
*/
@interface SDImageBlurTransformer : NSObject <SDImageTransformer>
@property (nonatomic, assign, readonly) CGFloat blurRadius;
- (nonnull instancetype)init NS_UNAVAILABLE;
+ (nonnull instancetype)transformerWithRadius:(CGFloat)blurRadius;
@end
#if SD_UIKIT || SD_MAC
/**
添加濾鏡
*/
@interface SDImageFilterTransformer: NSObject <SDImageTransformer>
@property (nonatomic, strong, readonly, nonnull) CIFilter *filter;
- (nonnull instancetype)init NS_UNAVAILABLE;
+ (nonnull instancetype)transformerWithFilter:(nonnull CIFilter *)filter;
@end
通過這幾個(gè)類可以對(duì)SDWebImageContextImageTransformer中value進(jìn)行自定義,以達(dá)到我們的需要
(2)、SDWebImageContextCacheKeyFilter - 圖片的指定緩存key,達(dá)到自定義緩存的目的,生成SDWebImageCacheKeyFilter對(duì)象。
一種是直接賦值給SDWebImageManager,另一種是放到context中處理。
在UIImageView調(diào)用加載圖片時(shí),設(shè)置下面代碼,自定義緩存key。
注意block回調(diào)是在global queue中進(jìn)行的。
設(shè)置SDWebImageCacheKeyFilter,在SD內(nèi)部根據(jù)URL緩存數(shù)據(jù)時(shí),會(huì)進(jìn)入block中,可以對(duì)url進(jìn)行自定義
SDWebImageManager.sharedManager.cacheKeyFilter =[SDWebImageCacheKeyFilter cacheKeyFilterWithBlock:^NSString * _Nullable(NSURL * _Nonnull url) {
url = [[NSURL alloc] initWithScheme:url.scheme host:url.host path:url.path];
return [url absoluteString];
}];
(3)、SDWebImageContextCacheSerializer - 緩存的圖片格式 SDWebImageCacheSerializer對(duì)象
一種是直接賦值給SDWebImageManager,另一種是放到context中處理。
當(dāng)webP格式的圖片data數(shù)據(jù)從磁盤讀取時(shí),會(huì)比普通格式的圖片讀取更加費(fèi)時(shí),所以我們下載完webP格式的data數(shù)據(jù),將其圖片格式變?yōu)镻NG/JPEG,然后將NSData數(shù)據(jù)放入磁盤,這樣下次讀取的時(shí)候速度會(huì)更快。
在UIImageView調(diào)用加載圖片時(shí),設(shè)置下面代碼,自定義緩存圖片格式。
注意block回調(diào)是在global queue中進(jìn)行的。
SDWebImageManager.sharedManager.cacheSerializer = [SDWebImageCacheSerializer cacheSerializerWithBlock:^NSData * _Nullable(UIImage * _Nonnull image, NSData * _Nullable data, NSURL * _Nullable imageURL) {
SDImageFormat format = [NSData sd_imageFormatForImageData:data];
switch (format) {
case SDImageFormatWebP:
return image.images ? data : nil;
default:
return data;
}
}];
歡迎關(guān)注我的公眾號(hào),專注iOS開發(fā)、大前端開發(fā)、跨平臺(tái)技術(shù)分享。
