2.7版本2012年9月8日发布
主要围绕渐进下载模块支持
1. UIButton+WebCache
- 新增BackgroundImage支持
//-------------------------2.7版本更新-block支持------------------------
//设置不同状态的按钮背景图片->按钮扩大和缩小
- (void)setBackgroundImageWithURL:(NSURL *)url;
- (void)setBackgroundImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder;
- (void)setBackgroundImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options;
#if NS_BLOCKS_AVAILABLE
- (void)setBackgroundImageWithURL:(NSURL *)url success:(SDWebImageSuccessBlock)success failure:(SDWebImageFailureBlock)failure;
- (void)setBackgroundImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder success:(SDWebImageSuccessBlock)success failure:(SDWebImageFailureBlock)failure;
- (void)setBackgroundImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options success:(SDWebImageSuccessBlock)success failure:(SDWebImageFailureBlock)failure;
#endif
//---------------------------------end--------------------------------
//--------------------2.7版本更新-BackgroundImage支持-------------------
- (void)setBackgroundImageWithURL:(NSURL *)url{
[self setBackgroundImageWithURL:url placeholderImage:nil];
}
- (void)setBackgroundImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder{
[self setBackgroundImageWithURL:url placeholderImage:placeholder options:0];
}
- (void)setBackgroundImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options{
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager cancelForDelegate:self];
[self setBackgroundImage:placeholder forState:UIControlStateNormal];
[self setBackgroundImage:placeholder forState:UIControlStateSelected];
[self setBackgroundImage:placeholder forState:UIControlStateHighlighted];
if (url){
NSDictionary *info = [NSDictionary dictionaryWithObject:@"background" forKey:@"type"];
[manager downloadWithURL:url delegate:self options:options userInfo:info];
}
}
#if NS_BLOCKS_AVAILABLE
- (void)setBackgroundImageWithURL:(NSURL *)url success:(SDWebImageSuccessBlock)success failure:(SDWebImageFailureBlock)failure{
[self setBackgroundImageWithURL:url placeholderImage:nil success:success failure:failure];
}
- (void)setBackgroundImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder success:(SDWebImageSuccessBlock)success failure:(SDWebImageFailureBlock)failure;{
[self setBackgroundImageWithURL:url placeholderImage:placeholder options:0 success:success failure:failure];
}
- (void)setBackgroundImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options success:(SDWebImageSuccessBlock)success failure:(SDWebImageFailureBlock)failure{
SDWebImageManager *manager = [SDWebImageManager sharedManager];
// Remove in progress downloader from queue
[manager cancelForDelegate:self];
[self setBackgroundImage:placeholder forState:UIControlStateNormal];
[self setBackgroundImage:placeholder forState:UIControlStateSelected];
[self setBackgroundImage:placeholder forState:UIControlStateHighlighted];
if (url){
NSDictionary *info = [NSDictionary dictionaryWithObject:@"background" forKey:@"type"];
[manager downloadWithURL:url delegate:self options:options userInfo:info success:success failure:failure];
}
}
#endif
//---------------------------------end--------------------------------
//----------------------------2.7版本更新-优化---------------------------
- (void)webImageManager:(SDWebImageManager *)imageManager didProgressWithPartialImage:(UIImage *)image forURL:(NSURL *)url userInfo:(NSDictionary *)info{
if ([[info valueForKey:@"type"] isEqualToString:@"background"]){
[self setBackgroundImage:image forState:UIControlStateNormal];
[self setBackgroundImage:image forState:UIControlStateSelected];
[self setBackgroundImage:image forState:UIControlStateHighlighted];
} else {
[self setImage:image forState:UIControlStateNormal];
[self setImage:image forState:UIControlStateSelected];
[self setImage:image forState:UIControlStateHighlighted];
}
}
- (void)webImageManager:(SDWebImageManager *)imageManager didFinishWithImage:(UIImage *)image forURL:(NSURL *)url userInfo:(NSDictionary *)info{
if ([[info valueForKey:@"type"] isEqualToString:@"background"]){
[self setBackgroundImage:image forState:UIControlStateNormal];
[self setBackgroundImage:image forState:UIControlStateSelected];
[self setBackgroundImage:image forState:UIControlStateHighlighted];
} else {
[self setImage:image forState:UIControlStateNormal];
[self setImage:image forState:UIControlStateSelected];
[self setImage:image forState:UIControlStateHighlighted];
}
}
//---------------------------------end--------------------------------
2. SDWebImageManager
- 新增SDWebImageOptions图片模式渐进下载
typedef enum{
//如果下载失败,还会继续尝试下载
SDWebImageRetryFailed = 1 << 0,
//滑动的时候Scrollview不下载,手从屏幕上移走,Scrollview开始减速的时候才会开始下载图片
SDWebImageLowPriority = 1 << 1,
//禁止磁盘缓存,只有内存缓存
SDWebImageCacheMemoryOnly = 1 << 2,
//------------------2.7版本更新-渐进下载----------------------
//正常情况图片下载完成,然后一次性显示,设置该选项那么图片边下载边显示
SDWebImageProgressiveDownload = 1 << 3
//--------------------------end----------------------------
} SDWebImageOptions;
- 增加了block回调支持
//------------------2.7版本更新-增加block支持----------------------
#if NS_BLOCKS_AVAILABLE
typedef void(^SDWebImageSuccessBlock)(UIImage *image, BOOL cached);
typedef void(^SDWebImageFailureBlock)(NSError *error);
#endif
//--------------------------end-----------------------------
- 新增URL缓存过滤器block
//------------------2.7版本更新-过滤URL----------------------
//[[SDWebImageManager sharedManager] setCacheKeyFilter:^(NSURL *url){
// url = [[NSURL alloc] initWithScheme:url.scheme host:url.host path:url.path];
// return [url absoluteString];
//}];
#if NS_BLOCKS_AVAILABLE
typedef NSString *(^CacheKeyFilter)(NSURL *url);
@property (strong) CacheKeyFilter cacheKeyFilter;
#endif
//--------------------------end----------------------------
- 废弃了一个方法
//------------------2.7版本更新-废弃----------------------
- (UIImage *)imageWithURL:(NSURL *)url __attribute__ ((deprecated));
//--------------------------end----------------------------
- 新增一个下载重载方法
//------------------2.7版本更新-方法重载----------------------
//如果不在缓存中,则在给定URL处下载图像,否则返回缓存版本
- (void)downloadWithURL:(NSURL *)url delegate:(id)delegate options:(SDWebImageOptions)options userInfo:(NSDictionary *)info;
//--------------------------end-----------------------------
- 新增下载缓存信息集合
@interface SDWebImageManager : NSObject {
NSMutableArray *downloaders;
NSMutableDictionary *downloaderForURL;
NSMutableArray *failedURLs;
NSMutableArray *downloadDelegates;
NSMutableArray *cacheDelegates;
NSMutableArray *cacheURLs;
//------------------2.7版本更新-缓存信息----------------------
NSMutableArray *downloadInfo;
//--------------------------end----------------------------
}
+ (id)sharedManager;
//------------------2.7版本更新-兼容block----------------------
#if NS_BLOCKS_AVAILABLE
@synthesize cacheKeyFilter;
#endif
//--------------------------end------------------------------
//-----------------------2.7版本更新-优化-----------------------
- (void)downloadWithURL:(NSURL *)url delegate:(id)delegate options:(SDWebImageOptions)options userInfo:(NSDictionary *)userInfo{
//非常常见的错误是使用NSString对象而不是NSURL发送URL。出于某种奇怪的原因,
//XCode不会为这种类型不匹配抛出任何警告。在这里,我们通过允许url作为NSString传递来防止这个错误。
if ([url isKindOfClass:NSString.class]){
url = [NSURL URLWithString:(NSString *)url];
} else if (![url isKindOfClass:NSURL.class]){
//防止由于NSNull等常见错误值而导致的一些常见崩溃。例如零
url = nil;
}
if (!url || !delegate || (!(options & SDWebImageRetryFailed) && [failedURLs containsObject:url])){
return;
}
//检查磁盘上的缓存异步,这样我们就不会阻塞主线程
[cacheDelegates addObject:delegate];
[cacheURLs addObject:url];
NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:
delegate,
@"delegate",
url,
@"url",
[NSNumber numberWithInt:options],
@"options",
userInfo ? userInfo : [NSNull null],
@"userInfo",
nil];
[[SDImageCache sharedImageCache] queryDiskCacheForKey:[self cacheKeyForURL:url] delegate:self userInfo:info];
}
//-----------------------------end----------------------------
//-----------------------2.7版本更新-支持block-----------------------
- (void)downloadWithURL:(NSURL *)url delegate:(id)delegate options:(SDWebImageOptions)options userInfo:(NSDictionary *)userInfo success:(SDWebImageSuccessBlock)success failure:(SDWebImageFailureBlock)failure{
//由于iOS版本需要向后压缩而没有块
//所以从上面重复的逻辑非常常见的错误是使用NSString对象而不是NSURL发送URL。出于某种奇怪的原因,
//XCode不会为这种类型不匹配抛出任何警告。在这里,我们通过允许url作为NSString传递来防止这个错误。
if ([url isKindOfClass:NSString.class]){
url = [NSURL URLWithString:(NSString *)url];
}
if (!url || !delegate || (!(options & SDWebImageRetryFailed) && [failedURLs containsObject:url])){
return;
}
//检查磁盘上的缓存异步,这样我们就不会阻塞主线程
[cacheDelegates addObject:delegate];
[cacheURLs addObject:url];
SDWebImageSuccessBlock successCopy = [success copy];
SDWebImageFailureBlock failureCopy = [failure copy];
NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:
delegate, @"delegate",
url, @"url",
[NSNumber numberWithInt:options], @"options",
userInfo ? userInfo : [NSNull null], @"userInfo",
successCopy, @"success",
failureCopy, @"failure",
nil];
SDWIRelease(successCopy);
SDWIRelease(failureCopy);
[[SDImageCache sharedImageCache] queryDiskCacheForKey:[self cacheKeyForURL:url] delegate:self userInfo:info];
}
#endif
//--------------------------------end------------------------------
- (void)cancelForDelegate:(id)delegate{
NSUInteger idx;
while ((idx = [cacheDelegates indexOfObjectIdenticalTo:delegate]) != NSNotFound){
[cacheDelegates removeObjectAtIndex:idx];
[cacheURLs removeObjectAtIndex:idx];
}
while ((idx = [downloadDelegates indexOfObjectIdenticalTo:delegate]) != NSNotFound){
SDWebImageDownloader *downloader = SDWIReturnRetained([downloaders objectAtIndex:idx]);
//----------------------2.7版本更新-功能更新---------------------
[downloadInfo removeObjectAtIndex:idx];
//----------------------------end-----------------------------
[downloadDelegates removeObjectAtIndex:idx];
[downloaders removeObjectAtIndex:idx];
if (![downloaders containsObject:downloader]){
//没有更多的委托在等待这个下载,取消它
[downloader cancel];
[downloaderForURL removeObjectForKey:downloader.url];
}
SDWIRelease(downloader);
}
}
- (void)imageCache:(SDImageCache *)imageCache didFindImage:(UIImage *)image forKey:(NSString *)key userInfo:(NSDictionary *)info{
NSURL *url = [info objectForKey:@"url"];
id delegate = [info objectForKey:@"delegate"];
NSUInteger idx = [self indexOfDelegate:delegate waitingForURL:url];
if (idx == NSNotFound){
//请求已被取消
return;
}
if ([delegate respondsToSelector:@selector(webImageManager:didFinishWithImage:)]){
[delegate performSelector:@selector(webImageManager:didFinishWithImage:) withObject:self withObject:image];
}
if ([delegate respondsToSelector:@selector(webImageManager:didFinishWithImage:forURL:)]){
objc_msgSend(delegate, @selector(webImageManager:didFinishWithImage:forURL:), self, image, url);
}
//--------------------------2.7版本更新-优化--------------------------
if ([delegate respondsToSelector:@selector(webImageManager:didFinishWithImage:forURL:userInfo:)]){
NSDictionary *userInfo = [info objectForKey:@"userInfo"];
if ([userInfo isKindOfClass:NSNull.class]){
userInfo = nil;
}
objc_msgSend(delegate, @selector(webImageManager:didFinishWithImage:forURL:userInfo:), self, image, url, userInfo);
}
//--------------------------------end-------------------------------
#if NS_BLOCKS_AVAILABLE
if ([info objectForKey:@"success"]){
SDWebImageSuccessBlock success = [info objectForKey:@"success"];
success(image, YES);
}
#endif
[cacheDelegates removeObjectAtIndex:idx];
[cacheURLs removeObjectAtIndex:idx];
}
- (void)imageCache:(SDImageCache *)imageCache didNotFindImageForKey:(NSString *)key userInfo:(NSDictionary *)info{
NSURL *url = [info objectForKey:@"url"];
id delegate = [info objectForKey:@"delegate"];
SDWebImageOptions options = [[info objectForKey:@"options"] intValue];
NSUInteger idx = [self indexOfDelegate:delegate waitingForURL:url];
if (idx == NSNotFound){
//请求已被取消
return;
}
[cacheDelegates removeObjectAtIndex:idx];
[cacheURLs removeObjectAtIndex:idx];
//为相同的URL共享相同的下载加载程序,所以我们不会多次下载相同的URL
SDWebImageDownloader *downloader = [downloaderForURL objectForKey:url];
if (!downloader){
downloader = [SDWebImageDownloader downloaderWithURL:url delegate:self userInfo:info lowPriority:(options & SDWebImageLowPriority)];
[downloaderForURL setObject:downloader forKey:url];
} else {
//重用共享下载器
downloader.lowPriority = (options & SDWebImageLowPriority);
}
//------------------------2.7版本更新-优化----------------------
if ((options & SDWebImageProgressiveDownload) && !downloader.progressive){
//根据需要提供渐进式下载支持
downloader.progressive = YES;
}
//----------------------------end-----------------------------
[downloadInfo addObject:info];
[downloadDelegates addObject:delegate];
[downloaders addObject:downloader];
}
- (void)imageDownloader:(SDWebImageDownloader *)downloader didFinishWithImage:(UIImage *)image{
SDWIRetain(downloader);
SDWebImageOptions options = [[downloader.userInfo objectForKey:@"options"] intValue];
//用这个下载器通知所有下载delegate
for (NSInteger idx = (NSInteger)[downloaders count] - 1; idx >= 0; idx--){
NSUInteger uidx = (NSUInteger)idx;
SDWebImageDownloader *aDownloader = [downloaders objectAtIndex:uidx];
if (aDownloader == downloader){
id delegate = [downloadDelegates objectAtIndex:uidx];
SDWIRetain(delegate);
SDWIAutorelease(delegate);
if (image){
if ([delegate respondsToSelector:@selector(webImageManager:didFinishWithImage:)]){
[delegate performSelector:@selector(webImageManager:didFinishWithImage:) withObject:self withObject:image];
}
if ([delegate respondsToSelector:@selector(webImageManager:didFinishWithImage:forURL:)]){
objc_msgSend(delegate, @selector(webImageManager:didFinishWithImage:forURL:), self, image, downloader.url);
}
//-------------------2.7版本更新-优化-新增方法重载-------------------
if ([delegate respondsToSelector:@selector(webImageManager:didFinishWithImage:forURL:userInfo:)]){
NSDictionary *userInfo = [[downloadInfo objectAtIndex:uidx] objectForKey:@"userInfo"];
if ([userInfo isKindOfClass:NSNull.class]){
userInfo = nil;
}
objc_msgSend(delegate, @selector(webImageManager:didFinishWithImage:forURL:userInfo:), self, image, downloader.url, userInfo);
}
//--------------------------------end---------------------------
//--------------2.7版本更新-block支持优化----------------
#if NS_BLOCKS_AVAILABLE
if ([[downloadInfo objectAtIndex:uidx] objectForKey:@"success"]){
SDWebImageSuccessBlock success = [[downloadInfo objectAtIndex:uidx] objectForKey:@"success"];
success(image, NO);
}
#endif
//-------------------------end------------------------
} else {
if ([delegate respondsToSelector:@selector(webImageManager:didFailWithError:)]){
[delegate performSelector:@selector(webImageManager:didFailWithError:) withObject:self withObject:nil];
}
if ([delegate respondsToSelector:@selector(webImageManager:didFailWithError:forURL:)]){
objc_msgSend(delegate, @selector(webImageManager:didFailWithError:forURL:), self, nil, downloader.url);
}
//-------------------2.7版本更新-优化-新增方法重载-------------------
if ([delegate respondsToSelector:@selector(webImageManager:didFailWithError:forURL:userInfo:)]){
NSDictionary *userInfo = [[downloadInfo objectAtIndex:uidx] objectForKey:@"userInfo"];
if ([userInfo isKindOfClass:NSNull.class]){
userInfo = nil;
}
objc_msgSend(delegate, @selector(webImageManager:didFailWithError:forURL:userInfo:), self, nil, downloader.url, userInfo);
}
//--------------------------------end---------------------------
#if NS_BLOCKS_AVAILABLE
if ([[downloadInfo objectAtIndex:uidx] objectForKey:@"failure"]){
SDWebImageFailureBlock failure = [[downloadInfo objectAtIndex:uidx] objectForKey:@"failure"];
failure(nil);
}
#endif
}
[downloaders removeObjectAtIndex:uidx];
[downloadInfo removeObjectAtIndex:uidx];
[downloadDelegates removeObjectAtIndex:uidx];
}
}
if (image){
//将图像存储在缓存中
[[SDImageCache sharedImageCache] storeImage:image
imageData:downloader.imageData
forKey:[self cacheKeyForURL:downloader.url]
toDisk:!(options & SDWebImageCacheMemoryOnly)];
} else if (!(options & SDWebImageRetryFailed)){
// 无法从这个URL下载图像,将URL标记为failed,这样我们就不会一次又一次地尝试失败
//(只有在SDWebImageRetryFailed未被激活时才这样做)
[failedURLs addObject:downloader.url];
}
//释放下载器
[downloaderForURL removeObjectForKey:downloader.url];
SDWIRelease(downloader);
}
- (void)imageDownloader:(SDWebImageDownloader *)downloader didFailWithError:(NSError *)error{
SDWIRetain(downloader);
//用这个下载器通知所有下载delegate
for (NSInteger idx = (NSInteger)[downloaders count] - 1; idx >= 0; idx--){
NSUInteger uidx = (NSUInteger)idx;
SDWebImageDownloader *aDownloader = [downloaders objectAtIndex:uidx];
if (aDownloader == downloader){
id delegate = [downloadDelegates objectAtIndex:uidx];
SDWIRetain(delegate);
SDWIAutorelease(delegate);
if ([delegate respondsToSelector:@selector(webImageManager:didFailWithError:)]){
[delegate performSelector:@selector(webImageManager:didFailWithError:) withObject:self withObject:error];
}
if ([delegate respondsToSelector:@selector(webImageManager:didFailWithError:forURL:)]){
objc_msgSend(delegate, @selector(webImageManager:didFailWithError:forURL:), self, error, downloader.url);
}
//-------------------2.7版本更新-优化-新增方法重载-------------------
if ([delegate respondsToSelector:@selector(webImageManager:didFailWithError:forURL:userInfo:)]){
NSDictionary *userInfo = [[downloadInfo objectAtIndex:uidx] objectForKey:@"userInfo"];
if ([userInfo isKindOfClass:NSNull.class])
{
userInfo = nil;
}
objc_msgSend(delegate, @selector(webImageManager:didFailWithError:forURL:userInfo:), self, error, downloader.url, userInfo);
}
//--------------------------------end---------------------------
//--------------2.7版本更新-block支持优化----------------
#if NS_BLOCKS_AVAILABLE
if ([[downloadInfo objectAtIndex:uidx] objectForKey:@"failure"]){
SDWebImageFailureBlock failure = [[downloadInfo objectAtIndex:uidx] objectForKey:@"failure"];
failure(error);
}
#endif
//-------------------------end------------------------
[downloaders removeObjectAtIndex:uidx];
[downloadInfo removeObjectAtIndex:uidx];
[downloadDelegates removeObjectAtIndex:uidx];
}
}
[downloaderForURL removeObjectForKey:downloader.url];
SDWIRelease(downloader);
}
//--------------------------2.7版本更新-新增功能----------------------------
- (void)imageDownloader:(SDWebImageDownloader *)downloader didUpdatePartialImage:(UIImage *)image{
//用这个下载器通知所有下载delegate
for (NSInteger idx = (NSInteger)[downloaders count] - 1; idx >= 0; idx--){
NSUInteger uidx = (NSUInteger)idx;
SDWebImageDownloader *aDownloader = [downloaders objectAtIndex:uidx];
if (aDownloader == downloader){
id delegate = [downloadDelegates objectAtIndex:uidx];
SDWIRetain(delegate);
SDWIAutorelease(delegate);
if ([delegate respondsToSelector:@selector(webImageManager:didProgressWithPartialImage:forURL:)]){
objc_msgSend(delegate, @selector(webImageManager:didProgressWithPartialImage:forURL:), self, image, downloader.url);
}
if ([delegate respondsToSelector:@selector(webImageManager:didProgressWithPartialImage:forURL:userInfo:)]){
NSDictionary *userInfo = [[downloadInfo objectAtIndex:uidx] objectForKey:@"userInfo"];
if ([userInfo isKindOfClass:NSNull.class]){
userInfo = nil;
}
objc_msgSend(delegate, @selector(webImageManager:didProgressWithPartialImage:forURL:userInfo:), self, image, downloader.url, userInfo);
}
}
}
}
//----------------------------------end------------------------------------
3. SDWebImageDownloader
- 新增三个属性
@interface SDWebImageDownloader : NSObject{
@private
NSURL *url;
SDWIWeak id delegate;
NSURLConnection *connection;
NSMutableData *imageData;
id userInfo;
BOOL lowPriority;
//-----------------------2.7版本更新-功能优化-----------------------
NSUInteger expectedSize;
BOOL progressive;
size_t width, height;
//-----------------------------end-------------------------------
}
//-----------------------2.7版本更新-功能优化--------------
//如果设置为YES,则启用渐进式下载支持
//正常情况图片下载完成,然后一次性显示
//设置为YES之后,图片边下载边显示
@property (nonatomic, readwrite) BOOL progressive;
//-----------------------------end----------------------
- 支持渐进下载传递NSData-网络请求回调中优化
- (void)connection:(NSURLConnection *)aConnection didReceiveResponse:(NSURLResponse *)response{
//-----------------------------2.7版本更新-功能优化-------------------------
if (![response respondsToSelector:@selector(statusCode)] || [((NSHTTPURLResponse *)response) statusCode] < 400){
expectedSize = response.expectedContentLength > 0 ? (NSUInteger)response.expectedContentLength : 0;
self.imageData = SDWIReturnAutoreleased([[NSMutableData alloc] initWithCapacity:expectedSize]);
//----------------------------------end----------------------------------
} else {
[aConnection cancel];
[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:nil];
if ([delegate respondsToSelector:@selector(imageDownloader:didFailWithError:)]){
NSError *error = [[NSError alloc] initWithDomain:NSURLErrorDomain
code:[((NSHTTPURLResponse *)response) statusCode]
userInfo:nil];
[delegate performSelector:@selector(imageDownloader:didFailWithError:) withObject:self withObject:error];
SDWIRelease(error);
}
self.connection = nil;
self.imageData = nil;
}
}
- 下载器代理渐进下载回调
- (void)connection:(NSURLConnection *)aConnection didReceiveData:(NSData *)data{
[imageData appendData:data];
//-----------------------------2.7版本更新-功能优化-------------------------
if (&CGImageSourceCreateImageAtIndex == NULL){
//ImageIO在iOS < 4中不存在
self.progressive = NO;
}
if (self.progressive && expectedSize > 0 && [delegate respondsToSelector:@selector(imageDownloader:didUpdatePartialImage:)]){
//以下代码来自http://www.cocoaintheshell.com/2011/05/progressies-download-imageio/
//感谢作者@Nyx0uf
//获取下载的总字节数
const NSUInteger totalSize = [imageData length];
//更新数据源时,我们必须传递所有数据,而不仅仅是新字节
CGImageSourceRef imageSource = CGImageSourceCreateIncremental(NULL);
#if __has_feature(objc_arc)
CGImageSourceUpdateData(imageSource, (__bridge CFDataRef)imageData, totalSize == expectedSize);
#else
CGImageSourceUpdateData(imageSource, (CFDataRef)imageData, totalSize == expectedSize);
#endif
if (width + height == 0){
CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, NULL);
if (properties){
CFTypeRef val = CFDictionaryGetValue(properties, kCGImagePropertyPixelHeight);
if (val) CFNumberGetValue(val, kCFNumberLongType, &height);
val = CFDictionaryGetValue(properties, kCGImagePropertyPixelWidth);
if (val) CFNumberGetValue(val, kCFNumberLongType, &width);
CFRelease(properties);
}
}
if (width + height > 0 && totalSize < expectedSize){
//创建图像
CGImageRef partialImageRef = CGImageSourceCreateImageAtIndex(imageSource, 0, NULL);
#ifdef TARGET_OS_IPHONE
//iOS变形图像的变通方法
if (partialImageRef){
const size_t partialHeight = CGImageGetHeight(partialImageRef);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef bmContext = CGBitmapContextCreate(NULL, width, height, 8, width * 4, colorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst);
CGColorSpaceRelease(colorSpace);
if (bmContext){
CGContextDrawImage(bmContext, (CGRect){.origin.x = 0.0f, .origin.y = 0.0f, .size.width = width, .size.height = partialHeight}, partialImageRef);
CGImageRelease(partialImageRef);
partialImageRef = CGBitmapContextCreateImage(bmContext);
CGContextRelease(bmContext);
} else {
CGImageRelease(partialImageRef);
partialImageRef = nil;
}
}
#endif
if (partialImageRef){
UIImage *image = SDScaledImageForPath(url.absoluteString, [UIImage imageWithCGImage:partialImageRef]);
[[SDWebImageDecoder sharedImageDecoder] decodeImage:image
withDelegate:self
userInfo:[NSDictionary dictionaryWithObject:@"partial" forKey:@"type"]];
CGImageRelease(partialImageRef);
}
}
CFRelease(imageSource);
}
//----------------------------------end----------------------------------
}
- (void)imageDecoder:(SDWebImageDecoder *)decoder didFinishDecodingImage:(UIImage *)image userInfo:(NSDictionary *)aUserInfo{
//-----------------------------2.7版本更新-功能优化-------------------------
if ([[aUserInfo valueForKey:@"type"] isEqualToString:@"partial"]){
[delegate imageDownloader:self didUpdatePartialImage:image];
} else {
[delegate performSelector:@selector(imageDownloader:didFinishWithImage:) withObject:self withObject:image];
}
//----------------------------------end----------------------------------
}
4. SDImageCache
- 增加缓存监控
//---------------2.7版本更新-新增功能--------------------
//设置全局最大缓存年龄
+ (void) setMaxCacheAge:(NSInteger) maxCacheAge;
//获取磁盘缓存中的映像数
- (int)getDiskCount;
//获取内存缓存中图像的总大小
- (int)getMemorySize;
//获取内存缓存中的图像数量
- (NSUInteger)getMemoryCount;
//---------------------------end----------------------
- 缓存释放优化
//---------------2.7版本更新-新增功能-内存--------------------
static natural_t minFreeMemLeft = 1024*1024*12; // reserve 12MB RAM
// inspired by http://stackoverflow.com/questions/5012886/knowing-available-ram-on-an-ios-device
//确定iOS设备上的可用RAM量
static natural_t get_free_memory(void){
mach_port_t host_port;
mach_msg_type_number_t host_size;
vm_size_t pagesize;
host_port = mach_host_self();
host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
host_page_size(host_port, &pagesize);
vm_statistics_data_t vm_stat;
if (host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size) != KERN_SUCCESS){
NSLog(@"Failed to fetch vm statistics");
return 0;
}
//统计数据以字节为单位
natural_t mem_free = vm_stat.free_count * pagesize;
return mem_free;
}
//---------------------------end----------------------
*********
- (void)storeImage:(UIImage *)image imageData:(NSData *)data forKey:(NSString *)key toDisk:(BOOL)toDisk{
if (!image || !key){
return;
}
//-----------------------2.7版本更新-功能优化-----------------------
if (get_free_memory() < minFreeMemLeft){
[memCache removeAllObjects];
}
//------------------------------end------------------------------
[memCache setObject:image forKey:key];
if (toDisk){
NSArray *keyWithData;
if (data){
keyWithData = [NSArray arrayWithObjects:key, data, nil];
} else{
keyWithData = [NSArray arrayWithObjects:key, nil];
}
NSInvocationOperation *operation = SDWIReturnAutoreleased([[NSInvocationOperation alloc] initWithTarget:self
selector:@selector(storeKeyWithDataToDisk:)
object:keyWithData]);
[cacheInQueue addOperation:operation];
}
}
- (UIImage *)imageFromKey:(NSString *)key fromDisk:(BOOL)fromDisk{
if (key == nil){
return nil;
}
UIImage *image = [memCache objectForKey:key];
if (!image && fromDisk){
image = SDScaledImageForPath(key, [NSData dataWithContentsOfFile:[self cachePathForKey:key]]);
if (image){
//-----------------------2.7版本更新-功能优化-----------------------
if (get_free_memory() < minFreeMemLeft){
[memCache removeAllObjects];
}
//------------------------------end------------------------------
[memCache setObject:image forKey:key];
}
}
return image;
}
- (void)notifyDelegate:(NSDictionary *)arguments{
NSString *key = [arguments objectForKey:@"key"];
id delegate = [arguments objectForKey:@"delegate"];
NSDictionary *info = [arguments objectForKey:@"userInfo"];
UIImage *image = [arguments objectForKey:@"image"];
if (image){
//-----------------------2.7版本更新-功能优化-----------------------
if (get_free_memory() < minFreeMemLeft){
[memCache removeAllObjects];
}
//------------------------------end------------------------------
[memCache setObject:image forKey:key];
if ([delegate respondsToSelector:@selector(imageCache:didFindImage:forKey:userInfo:)]){
[delegate imageCache:self didFindImage:image forKey:key userInfo:info];
}
} else {
if ([delegate respondsToSelector:@selector(imageCache:didNotFindImageForKey:userInfo:)]){
[delegate imageCache:self didNotFindImageForKey:key userInfo:info];
}
}
}
//----------------------2.7版本更新-新增功能------------------------
+ (void) setMaxCacheAge:(NSInteger)maxCacheAge{
cacheMaxCacheAge = maxCacheAge;
}
- (int)getDiskCount{
int count = 0;
NSDirectoryEnumerator *fileEnumerator = [[NSFileManager defaultManager] enumeratorAtPath:diskCachePath];
for (NSString *fileName in fileEnumerator){
count += 1;
}
return count;
}
- (int)getMemorySize{
int size = 0;
for(id key in [memCache allKeys]){
UIImage *img = [memCache valueForKey:key];
size += [UIImageJPEGRepresentation(img, 0) length];
}
return size;
}
- (NSUInteger)getMemoryCount{
return [[memCache allKeys] count];
}
//----------------------------end--------------------------------
5. SDWebImagePrefetcher
- 增加下载模式支持
//--------------------2.7版本更新-图片下载---------------------
@property (nonatomic, assign) SDWebImageOptions options;
//----------------------------end---------------------------
//---------------2.7版本更新-新增功能----------------
@synthesize options;
//----------------------end-----------------------
+ (SDWebImagePrefetcher *)sharedImagePrefetcher{
if (instance == nil){
instance = [[SDWebImagePrefetcher alloc] init];
instance.maxConcurrentDownloads = 3;
//---------------2.7版本更新-新增功能----------------
instance.options = (SDWebImageLowPriority);
//----------------------end-----------------------
}
return instance;
}
6. SDWebImageCompat
- 针对图片数据类型兼容
NS_INLINE UIImage *SDScaledImageForPath(NSString *path, NSObject *imageOrData){
if (!imageOrData){
return nil;
}
//---------------------2.7版本更新-代码优化---------------------
UIImage *image = nil;
if ([imageOrData isKindOfClass:[NSData class]]){
image = [[UIImage alloc] initWithData:(NSData *)imageOrData];
} else if ([imageOrData isKindOfClass:[UIImage class]]){
image = SDWIReturnRetained((UIImage *)imageOrData);
} else {
return nil;
}
//----------------------------end----------------------------
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]){
CGFloat scale = 1.0;
if (path.length >= 8){
NSRange range = [path rangeOfString:@"@2x." options:0 range:NSMakeRange(path.length - 8, 5)];
if (range.location != NSNotFound){
scale = 2.0;
}
}
UIImage *scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:UIImageOrientationUp];
SDWISafeRelease(image)
image = scaledImage;
}
return SDWIReturnAutoreleased(image);
}