SDWebImage note
- Basic Information
- Global Note
- File Notes
- 0. SDWebImageCompat.h
- 1. SDWebImageDownloader.m
- 2. SDWebImageDownloader.m
- 3. SDWebImageDownloader.m
- 4. SDWebImageDownloader.m
- 5. SDWebImageDownloader.m
- 6. SDWebImageDownloader.m
- 7. SDWebImageDownloader.m
- 8. SDWebImageDownloaderOperation.m
- 9. SDWebImageDownloaderOperation.m
- 10. SDWebImageDownloaderOperation.m
- 11. SDWebImageDownloaderOperation.m
- 12. SDWebImageDownloaderOperation.m
- 13. SDWebImageDownloaderOperation.m
- 14. SDWebImageDownloaderOperation.m
- 15. SDWebImageDownloaderOperation.m
- 16. SDWebImageDownloaderOperation.m
- 17. SDWebImageDownloaderOperation.m
- 18. SDWebImageDownloaderOperation.m
- 19. SDImageCache.m
- 20. SDImageCache.m
- 21. SDImageCache.m
- 22. SDImageCache.m
- 23. SDImageCache.m
- 24. SDImageCache.m
- 25. SDImageCache.m
- 26. SDImageCache.m
- 27. SDImageCache.m
- 28. SDWebImageCompat.m
- 29. NSData+ImageContentType.m
- 30. UIImage+GIF.m
- 31. SDWebImageDecoder.m
- 32. SDImageCache.m
- 33. NSFileManager.h
- 34. NSDictionary.h
- 35. SDWebImageManager.m
- 36. SDWebImageManager.m
- 37. SDWebImageManager.m
- 38. UIImage+MultiFormat.m
- 39. UIView+WebCacheOperation.m
- 40. UIView+WebCacheOperation.m
- 41. UIImageView+WebCache.m
- 42. UIImageView+WebCache.m
- Summarize
Basic Information
- Name : SDWebImage
- Site : https://github.com/rs/SDWebImage
- Repo : https://github.com/rs/SDWebImage
- Revision : 0da78a4ce6485d8d4c23d348d355fabad7c227f3
- Description : 经典的、异步下载图片的、带缓存的库
Global Note
File Notes
0. SDWebImageCompat.h
- Path : /SDWebImage/SDWebImageCompat.h
- Line : 60 - 72
- Note :
#define dispatch_main_sync_safe(block)\
if ([NSThread isMainThread]) {\
block();\
} else {\
dispatch_sync(dispatch_get_main_queue(), block);\
}
#define dispatch_main_async_safe(block)\
if ([NSThread isMainThread]) {\
block();\
} else {\
dispatch_async(dispatch_get_main_queue(), block);\
}
方便的dispatch_main 保证主线程运行
1. SDWebImageDownloader.m
- Path : /SDWebImage/SDWebImageDownloader.m
- Line : 33 - 33
- Note :
if (NSClassFromString(@"SDNetworkActivityIndicator")) {
判断某个类是否存在
2. SDWebImageDownloader.m
- Path : /SDWebImage/SDWebImageDownloader.m
- Line : 35 - 38
- Note :
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
id activityIndicator = [NSClassFromString(@"SDNetworkActivityIndicator") performSelector:NSSelectorFromString(@"sharedActivityIndicator")];
#pragma clang diagnostic pop
动态调用单例方法
3. SDWebImageDownloader.m
- Path : /SDWebImage/SDWebImageDownloader.m
- Line : 67 - 68
- Note :
_downloadQueue = [NSOperationQueue new];
_downloadQueue.maxConcurrentOperationCount = 6;
NSOperation相比GCD的优势,可配置并行最大线程数
4. SDWebImageDownloader.m
- Path : /SDWebImage/SDWebImageDownloader.m
- Line : 111 - 113
- Note :
- (void)setOperationClass:(Class)operationClass {
_operationClass = operationClass ?: [SDWebImageDownloaderOperation class];
}
这么动态配置执行的Class。
5. SDWebImageDownloader.m
- Path : /SDWebImage/SDWebImageDownloader.m
- Line : 207 - 207
- Note :
dispatch_barrier_sync(self.barrierQueue, ^{
_barrierQueue = dispatch_queue_create("com.hackemist.SDWebImageDownloaderBarrierQueue", DISPATCH_QUEUE_CONCURRENT);
在并行queue中的很方便的同步方法。
6. SDWebImageDownloader.m
- Path : /SDWebImage/SDWebImageDownloader.m
- Line : 214 - 224
- Note :
// Handle single download of simultaneous download request for the same URL
NSMutableArray *callbacksForURL = self.URLCallbacks[url];
NSMutableDictionary *callbacks = [NSMutableDictionary new];
if (progressBlock) callbacks[kProgressCallbackKey] = [progressBlock copy];
if (completedBlock) callbacks[kCompletedCallbackKey] = [completedBlock copy];
[callbacksForURL addObject:callbacks];
self.URLCallbacks[url] = callbacksForURL;
if (first) {
createCallback();
}
每个URL对应多个回调地址。可能同时多次请求相同URL地址,避免重复下载。
7. SDWebImageDownloader.m
- Path : /SDWebImage/SDWebImageDownloader.m
- Line : 187 - 192
- Note :
[wself.downloadQueue addOperation:operation];
if (wself.executionOrder == SDWebImageDownloaderLIFOExecutionOrder) {
// Emulate LIFO execution order by systematically adding new operations as last operation's dependency
[wself.lastAddedOperation addDependency:operation];
wself.lastAddedOperation = operation;
}
启动下载。如果是Last In First Out,则把最后一个添加的任务的依赖设置为当前要添加的任务。
8. SDWebImageDownloaderOperation.m
- Path : /SDWebImage/SDWebImageDownloaderOperation.m
- Line : 33 - 33
- Note :
@property (assign, nonatomic) UIBackgroundTaskIdentifier backgroundTaskId;
后台任务ID
9. SDWebImageDownloaderOperation.m
- Path : /SDWebImage/SDWebImageDownloaderOperation.m
- Line : 77 - 92
- Note :
Class UIApplicationClass = NSClassFromString(@"UIApplication");
BOOL hasApplication = UIApplicationClass && [UIApplicationClass respondsToSelector:@selector(sharedApplication)];
if (hasApplication && [self shouldContinueWhenAppEntersBackground]) {
__weak __typeof__ (self) wself = self;
UIApplication * app = [UIApplicationClass performSelector:@selector(sharedApplication)];
self.backgroundTaskId = [app beginBackgroundTaskWithExpirationHandler:^{
__strong __typeof (wself) sself = wself;
if (sself) {
[sself cancel];
[app endBackgroundTask:sself.backgroundTaskId];
sself.backgroundTaskId = UIBackgroundTaskInvalid;
}
}];
}
后台,保证任务取消
10. SDWebImageDownloaderOperation.m
- Path : /SDWebImage/SDWebImageDownloaderOperation.m
- Line : 96 - 96
- Note :
self.connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:NO];
发起下载操作的NSURLConnection
11. SDWebImageDownloaderOperation.m
- Path : /SDWebImage/SDWebImageDownloaderOperation.m
- Line : 100 - 123
- Note :
[self.connection start];
if (self.connection) {
if (self.progressBlock) {
self.progressBlock(0, NSURLResponseUnknownLength);
}
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStartNotification object:self];
});
if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_5_1) {
// Make sure to run the runloop in our background thread so it can process downloaded data
// Note: we use a timeout to work around an issue with NSURLConnection cancel under iOS 5
// not waking up the runloop, leading to dead threads (see <https://github.com/rs/SDWebImage/issues/466)>
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 10, false);
}
else {
CFRunLoopRun();
}
if (!self.isFinished) {
[self.connection cancel];
[self connection:self.connection didFailWithError:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorTimedOut userInfo:@{NSURLErrorFailingURLErrorKey : self.request.URL}]];
}
发起下载。NSRunLoopRun() 启动后台线程的runloop。NSURLConnection 依赖RunLoop。
SDWebImage是个古老的库,兼容iOS5.1以下。
12. SDWebImageDownloaderOperation.m
- Path : /SDWebImage/SDWebImageDownloaderOperation.m
- Line : 155 - 167
- Note :
- (void)cancelInternalAndStop {
if (self.isFinished) return;
[self cancelInternal];
CFRunLoopStop(CFRunLoopGetCurrent());
}
- (void)cancelInternal {
if (self.isFinished) return;
[super cancel];
if (self.cancelBlock) self.cancelBlock();
if (self.connection) {
[self.connection cancel];
先cancel Connection,然后停止RunLoop。
13. SDWebImageDownloaderOperation.m
- Path : /SDWebImage/SDWebImageDownloaderOperation.m
- Line : 196 - 200
- Note :
- (void)setFinished:(BOOL)finished {
[self willChangeValueForKey:@"isFinished"];
_finished = finished;
[self didChangeValueForKey:@"isFinished"];
}
KVO
14. SDWebImageDownloaderOperation.m
- Path : /SDWebImage/SDWebImageDownloaderOperation.m
- Line : 213 - 225
- Note :
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
//'304 Not Modified' is an exceptional one
if (![response respondsToSelector:@selector(statusCode)] || ([((NSHTTPURLResponse *)response) statusCode] < 400 && [((NSHTTPURLResponse *)response) statusCode] != 304)) {
NSInteger expected = response.expectedContentLength > 0 ? (NSInteger)response.expectedContentLength : 0;
self.expectedSize = expected;
if (self.progressBlock) {
self.progressBlock(0, expected);
}
self.imageData = [[NSMutableData alloc] initWithCapacity:expected];
self.response = response;
看来有个 304 Not Modified 坑。
15. SDWebImageDownloaderOperation.m
- Path : /SDWebImage/SDWebImageDownloaderOperation.m
- Line : 231 - 239
- Note :
NSUInteger code = [((NSHTTPURLResponse *)response) statusCode];
//This is the case when server returns '304 Not Modified'. It means that remote image is not changed.
//In case of 304 we need just cancel the operation and return cached image from the cache.
if (code == 304) {
[self cancelInternal];
} else {
[self.connection cancel];
}
304 ,则直接返回缓存中的图片
16. SDWebImageDownloaderOperation.m
- Path : /SDWebImage/SDWebImageDownloaderOperation.m
- Line : 252 - 253
- Note :
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.imageData appendData:data];
收到数据。self.imageData 是从didReceiveResponse中开辟。
17. SDWebImageDownloaderOperation.m
- Path : /SDWebImage/SDWebImageDownloaderOperation.m
- Line : 256 - 266
- Note :
// The following code is from <http://www.cocoaintheshell.com/2011/05/progressive-images-download-imageio/>
// Thanks to the author @Nyx0uf
// Get the total bytes downloaded
const NSInteger totalSize = self.imageData.length;
// Update the data source, we must pass ALL the data, not just the new bytes
CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)self.imageData, NULL);
if (width + height == 0) {
CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, NULL);
渐进的加载图片……内存中绘制渐进效果的图片
18. SDWebImageDownloaderOperation.m
- Path : /SDWebImage/SDWebImageDownloaderOperation.m
- Line : 337 - 358
- Note :
+ (UIImageOrientation)orientationFromPropertyValue:(NSInteger)value {
switch (value) {
case 1:
return UIImageOrientationUp;
case 3:
return UIImageOrientationDown;
case 8:
return UIImageOrientationLeft;
case 6:
return UIImageOrientationRight;
case 2:
return UIImageOrientationUpMirrored;
case 4:
return UIImageOrientationDownMirrored;
case 5:
return UIImageOrientationLeftMirrored;
case 7:
return UIImageOrientationRightMirrored;
default:
return UIImageOrientationUp;
}
}
关于Orientation ,参考这篇文章 http://feihu.me/blog/2015/how-to-handle-image-orientation-on-iOS/
19. SDImageCache.m
- Path : /SDWebImage/SDImageCache.m
- Line : 14 - 35
- Note :
// See <https://github.com/rs/SDWebImage/pull/1141> for discussion
@interface AutoPurgeCache : NSCache
@end
@implementation AutoPurgeCache
- (id)init
{
self = [super init];
if (self) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(removeAllObjects) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
}
return self;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
}
@end
内存警告时清空缓存
20. SDImageCache.m
- Path : /SDWebImage/SDImageCache.m
- Line : 38 - 53
- Note :
// PNG signature bytes and data (below)
static unsigned char kPNGSignatureBytes[8] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
static NSData *kPNGSignatureData = nil;
BOOL ImageDataHasPNGPreffix(NSData *data);
BOOL ImageDataHasPNGPreffix(NSData *data) {
NSUInteger pngSignatureLength = [kPNGSignatureData length];
if ([data length] >= pngSignatureLength) {
if ([[data subdataWithRange:NSMakeRange(0, pngSignatureLength)] isEqualToData:kPNGSignatureData]) {
return YES;
}
}
return NO;
}
png文件前缀
21. SDImageCache.m
- Path : /SDWebImage/SDImageCache.m
- Line : 55 - 57
- Note :
FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
return image.size.height * image.size.width * image.scale * image.scale;
}
FOUNDATION_STATIC_INLINE 可以学习用用。 图片的cost计算方式。
22. SDImageCache.m
- Path : /SDWebImage/SDImageCache.m
- Line : 77 - 77
- Note :
instance = [self new];
[self new] 学习了。可以研究下 与[XXXX new]的区别。
23. SDImageCache.m
- Path : /SDWebImage/SDImageCache.m
- Line : 105 - 105
- Note :
_memCache = [[AutoPurgeCache alloc] init];
内存的缓存是NSCache。
24. SDImageCache.m
- Path : /SDWebImage/SDImageCache.m
- Line : 125 - 127
- Note :
dispatch_sync(_ioQueue, ^{
_fileManager = [NSFileManager new];
});
ioQueue
_ioQueue = dispatch_queue_create(“com.hackemist.SDWebImageCache”, DISPATCH_QUEUE_SERIAL);
25. SDImageCache.m
- Path : /SDWebImage/SDImageCache.m
- Line : 177 - 189
- Note :
- (NSString *)cachedFileNameForKey:(NSString *)key {
const char *str = [key UTF8String];
if (str == NULL) {
str = "";
}
unsigned char r[CC_MD5_DIGEST_LENGTH];
CC_MD5(str, (CC_LONG)strlen(str), r);
NSString *filename = [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%@",
r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7], r[8], r[9], r[10],
r[11], r[12], r[13], r[14], r[15], [[key pathExtension] isEqualToString:@""] ? @"" : [NSString stringWithFormat:@".%@", [key pathExtension]]];
return filename;
}
磁盘缓存文件名称
26. SDImageCache.m
- Path : /SDWebImage/SDImageCache.m
- Line : 213 - 238
- Note :
if (image && (recalculate || !data)) {
#if TARGET_OS_IPHONE
// We need to determine if the image is a PNG or a JPEG
// PNGs are easier to detect because they have a unique signature (http://www.w3.org/TR/PNG-Structure.html)
// The first eight bytes of a PNG file always contain the following (decimal) values:
// 137 80 78 71 13 10 26 10
// If the imageData is nil (i.e. if trying to save a UIImage directly or the image was transformed on download)
// and the image has an alpha channel, we will consider it PNG to avoid losing the transparency
int alphaInfo = CGImageGetAlphaInfo(image.CGImage);
BOOL hasAlpha = !(alphaInfo == kCGImageAlphaNone ||
alphaInfo == kCGImageAlphaNoneSkipFirst ||
alphaInfo == kCGImageAlphaNoneSkipLast);
BOOL imageIsPng = hasAlpha;
// But if we have an image data, we will look at the preffix
if ([imageData length] >= [kPNGSignatureData length]) {
imageIsPng = ImageDataHasPNGPreffix(imageData);
}
if (imageIsPng) {
data = UIImagePNGRepresentation(image);
}
else {
data = UIImageJPEGRepresentation(image, (CGFloat)1.0);
}
磁盘缓存时,且需要recalculate时,判断png。两种方法判断png。
- 是否有透明通道。alpha。
- 是否有png的格式magic number前缀。
PS:如果需要加载gif,这里注意不要recalculate,否则 再次从磁盘加载后就不是gif文件了(变为jpg文件)。
27. SDImageCache.m
- Path : /SDWebImage/SDImageCache.m
- Line : 276 - 278
- Note :
// this is an exception to access the filemanager on another queue than ioQueue, but we are using the shared instance
// from apple docs on NSFileManager: The methods of the shared NSFileManager object can be called from multiple threads safely.
exists = [[NSFileManager defaultManager] fileExistsAtPath:[self defaultCachePathForKey:key]];
sharedManager 线程安全的哦
28. SDWebImageCompat.m
- Path : /SDWebImage/SDWebImageCompat.m
- Line : 15 - 49
- Note :
inline UIImage *SDScaledImageForKey(NSString *key, UIImage *image) {
if (!image) {
return nil;
}
if ([image.images count] > 0) {
NSMutableArray *scaledImages = [NSMutableArray array];
for (UIImage *tempImage in image.images) {
[scaledImages addObject:SDScaledImageForKey(key, tempImage)];
}
return [UIImage animatedImageWithImages:scaledImages duration:image.duration];
}
else {
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
CGFloat scale = [UIScreen mainScreen].scale;
if (key.length >= 8) {
NSRange range = [key rangeOfString:@"@2x."];
if (range.location != NSNotFound) {
scale = 2.0;
}
range = [key rangeOfString:@"@3x."];
if (range.location != NSNotFound) {
scale = 3.0;
}
}
UIImage *scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation];
image = scaledImage;
}
return image;
}
}
缩放图片。本地存储时,存储缩放的图片
29. NSData+ImageContentType.m
- Path : /SDWebImage/NSData+ImageContentType.m
- Line : 11 - 40
- Note :
+ (NSString *)sd_contentTypeForImageData:(NSData *)data {
uint8_t c;
[data getBytes:&c length:1];
switch (c) {
case 0xFF:
return @"image/jpeg";
case 0x89:
return @"image/png";
case 0x47:
return @"image/gif";
case 0x49:
case 0x4D:
return @"image/tiff";
case 0x52:
// R as RIFF for WEBP
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 @"image/webp";
}
return nil;
}
return nil;
}
从文件头判断图片类型
30. UIImage+GIF.m
- Path : /SDWebImage/UIImage+GIF.m
- Line : 14 - 57
- Note :
+ (UIImage *)sd_animatedGIFWithData:(NSData *)data {
if (!data) {
return nil;
}
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
size_t count = CGImageSourceGetCount(source);
UIImage *animatedImage;
if (count <= 1) {
animatedImage = [[UIImage alloc] initWithData:data];
}
else {
NSMutableArray *images = [NSMutableArray array];
NSTimeInterval duration = 0.0f;
for (size_t i = 0; i < count; i++) {
CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL);
if (!image) {
continue;
}
duration += [self sd_frameDurationAtIndex:i source:source];
[images addObject:[UIImage imageWithCGImage:image scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp]];
CGImageRelease(image);
}
if (!duration) {
duration = (1.0f / 10.0f) * count;
}
animatedImage = [UIImage animatedImageWithImages:images duration:duration];
}
CFRelease(source);
return animatedImage;
}
使用CGImageSourceCreateWithData 读取Gif文件
31. SDWebImageDecoder.m
- Path : /SDWebImage/SDWebImageDecoder.m
- Line : 15 - 77
- Note :
+ (UIImage *)decodedImageWithImage:(UIImage *)image {
// while downloading huge amount of images
// autorelease the bitmap context
// and all vars to help system to free memory
// when there are memory warning.
// on iOS7, do not forget to call
// [[SDImageCache sharedImageCache] clearMemory];
if (image == nil) { // Prevent "CGBitmapContextCreateImage: invalid context 0x0" error
return nil;
}
@autoreleasepool{
// do not decode animated images
if (image.images) { return image; }
CGImageRef imageRef = image.CGImage;
CGImageAlphaInfo alpha = CGImageGetAlphaInfo(imageRef);
BOOL anyAlpha = (alpha == kCGImageAlphaFirst ||
alpha == kCGImageAlphaLast ||
alpha == kCGImageAlphaPremultipliedFirst ||
alpha == kCGImageAlphaPremultipliedLast);
if (anyAlpha) { return image; }
// current
CGColorSpaceModel imageColorSpaceModel = CGColorSpaceGetModel(CGImageGetColorSpace(imageRef));
CGColorSpaceRef colorspaceRef = CGImageGetColorSpace(imageRef);
bool unsupportedColorSpace = (imageColorSpaceModel == 0 || imageColorSpaceModel == -1 || imageColorSpaceModel == kCGColorSpaceModelCMYK || imageColorSpaceModel == kCGColorSpaceModelIndexed);
if (unsupportedColorSpace)
colorspaceRef = CGColorSpaceCreateDeviceRGB();
size_t width = CGImageGetWidth(imageRef);
size_t height = CGImageGetHeight(imageRef);
NSUInteger bytesPerPixel = 4;
NSUInteger bytesPerRow = bytesPerPixel * width;
NSUInteger bitsPerComponent = 8;
CGContextRef context = CGBitmapContextCreate(NULL,
width,
height,
bitsPerComponent,
bytesPerRow,
colorspaceRef,
kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst);
// Draw the image into the context and retrieve the new image, which will now have an alpha layer
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGImageRef imageRefWithAlpha = CGBitmapContextCreateImage(context);
UIImage *imageWithAlpha = [UIImage imageWithCGImage:imageRefWithAlpha scale:image.scale orientation:image.imageOrientation];
if (unsupportedColorSpace)
CGColorSpaceRelease(colorspaceRef);
CGContextRelease(context);
CGImageRelease(imageRefWithAlpha);
return imageWithAlpha;
}
}
decode image,优化图片加载速度
32. SDImageCache.m
- Path : /SDWebImage/SDImageCache.m
- Line : 506 - 536
- Note :
NSArray *resourceKeys = @[NSURLIsDirectoryKey, NSURLContentModificationDateKey, NSURLTotalFileAllocatedSizeKey];
// This enumerator prefetches useful properties for our cache files.
NSDirectoryEnumerator *fileEnumerator = [_fileManager enumeratorAtURL:diskCacheURL
includingPropertiesForKeys:resourceKeys
options:NSDirectoryEnumerationSkipsHiddenFiles
errorHandler:NULL];
NSDate *expirationDate = [NSDate dateWithTimeIntervalSinceNow:-self.maxCacheAge];
NSMutableDictionary *cacheFiles = [NSMutableDictionary dictionary];
NSUInteger currentCacheSize = 0;
// Enumerate all of the files in the cache directory. This loop has two purposes:
//
// 1. Removing files that are older than the expiration date.
// 2. Storing file attributes for the size-based cleanup pass.
NSMutableArray *urlsToDelete = [[NSMutableArray alloc] init];
for (NSURL *fileURL in fileEnumerator) {
NSDictionary *resourceValues = [fileURL resourceValuesForKeys:resourceKeys error:NULL];
// Skip directories.
if ([resourceValues[NSURLIsDirectoryKey] boolValue]) {
continue;
}
// Remove files that are older than the expiration date;
NSDate *modificationDate = resourceValues[NSURLContentModificationDateKey];
if ([[modificationDate laterDate:expirationDate] isEqualToDate:expirationDate]) {
[urlsToDelete addObject:fileURL];
continue;
}
利用文件系统存储文件的时间、大小等元数据来清理文件
33. NSFileManager.h
- Path : /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSFileManager.h
- Line : 442 - 442
- Note :
@interface NSDictionary<KeyType, ObjectType> (NSFileAttributes)
KeyType 和 ObjectType 。Objective C还有这个语法呀。类似泛型。
34. NSDictionary.h
- Path : /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSDictionary.h
- Line : 14 - 14
- Note :
@interface NSDictionary<__covariant KeyType, __covariant ObjectType> : NSObject <NSCopying, NSMutableCopying, NSSecureCoding, NSFastEnumeration>
NSDictionary的声明。泛型中的协变和逆变。
参考这篇文章:http://blog.sunnyxx.com/2015/06/12/objc-new-features-in-2015/
https://msdn.microsoft.com/zh-cn/library/dd799517.aspx
35. SDWebImageManager.m
- Path : /SDWebImage/SDWebImageManager.m
- Line : 131 - 134
- Note :
BOOL isFailedUrl = NO;
@synchronized (self.failedURLs) {
isFailedUrl = [self.failedURLs containsObject:url];
}
存储失败的url
36. SDWebImageManager.m
- Path : /SDWebImage/SDWebImageManager.m
- Line : 119 - 126
- Note :
if ([url isKindOfClass:NSString.class]) {
url = [NSURL URLWithString:(NSString *)url];
}
// Prevents app crashing on argument type error like sending NSNull instead of NSURL
if (![url isKindOfClass:NSURL.class]) {
url = nil;
}
纠正参数类型。判断参数类型。NSNull。
37. SDWebImageManager.m
- Path : /SDWebImage/SDWebImageManager.m
- Line : 305 - 306
- Note :
NSArray *copiedOperations = [self.runningOperations copy];
[copiedOperations makeObjectsPerformSelector:@selector(cancel)];
NSArray竟然有这个方法,Objective C真的开发者友好啊。
38. UIImage+MultiFormat.m
- Path : /SDWebImage/UIImage+MultiFormat.m
- Line : 51 - 71
- Note :
+(UIImageOrientation)sd_imageOrientationFromImageData:(NSData *)imageData {
UIImageOrientation result = UIImageOrientationUp;
CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)imageData, NULL);
if (imageSource) {
CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, NULL);
if (properties) {
CFTypeRef val;
int exifOrientation;
val = CFDictionaryGetValue(properties, kCGImagePropertyOrientation);
if (val) {
CFNumberGetValue(val, kCFNumberIntType, &exifOrientation);
result = [self sd_exifOrientationToiOSOrientation:exifOrientation];
} // else - if it's not set it remains at up
CFRelease((CFTypeRef) properties);
} else {
//NSLog(@"NO PROPERTIES, FAIL");
}
CFRelease(imageSource);
}
return result;
}
从Data获取orientation
39. UIView+WebCacheOperation.m
- Path : /SDWebImage/UIView+WebCacheOperation.m
- Line : 16 - 24
- Note :
- (NSMutableDictionary *)operationDictionary {
NSMutableDictionary *operations = objc_getAssociatedObject(self, &loadOperationKey);
if (operations) {
return operations;
}
operations = [NSMutableDictionary dictionary];
objc_setAssociatedObject(self, &loadOperationKey, operations, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
return operations;
}
每个UIView关联一个operation集合。(主要用于在Cell重用,或者对UIImageView重复加载url image时,取消之前的加载任务)
40. UIView+WebCacheOperation.m
- Path : /SDWebImage/UIView+WebCacheOperation.m
- Line : 43 - 43
- Note :
} else if ([operations conformsToProtocol:@protocol(SDWebImageOperation)]){
conformsToProtocol:@protocol 学习了。
41. UIImageView+WebCache.m
- Path : /SDWebImage/UIImageView+WebCache.m
- Line : 174 - 177
- Note :
- (void)addActivityIndicator {
if (!self.activityIndicator) {
self.activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:[self getIndicatorStyle]];
self.activityIndicator.translatesAutoresizingMaskIntoConstraints = NO;
看来新版本SDWebImage集成了indicator功能。
42. UIImageView+WebCache.m
- Path : /SDWebImage/UIImageView+WebCache.m
- Line : 44 - 46
- Note :
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock {
[self sd_cancelCurrentImageLoad];
objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
cancel掉之前对当前imageview的加载操作。
Summarize
Generated by XSourceNote at 2016-04-03 07:11:39 +0000