@SDWebImage提供一个UIImageView的类别以支持加载来自网络的远程图片。具有缓存管理、异步下载、同一个URL下载次数控制和优化等特征.
它提供了:
@目前来说,主要用到了"UIImageView+WebCache.h",给出一个代码示例:
它是UIImageView的一个类目,在要使用它的类中加入#import "UIImageView+WebCache.h",调用 setImageWithURL:placeholderImage:方法。从异步下载到缓存管理,一切都会为你处理。
@得到1个图片的url用SDWebImage缓存后的文件名
NSLog(@"%s__%d__|%@",__FUNCTION__,__LINE__,[[SDImageCache sharedImageCache] cachedFileNameForKey:@"http://c.hiphotos.baidu.com/image/w%3D2048/sign=396e9d640b23dd542173a068e531b2de/cc11728b4710b9123a8117fec1fdfc039245226a.jpg"]);
不可见的ImageView加载图片的必要性大大降低,取消其加载任务可以加速其他图片的加载,也有助于减少资源占用。特别是在可以reuse的view中,一定要记得在prepareForReuse中取消掉当前imageView的图片加载。否则之前的加载任务,还会影响到当前reuse以前视图的imageView.
- (void)prepareForReuse
{
[super prepareForReuse];
[_imageView cancelCurrentImageLoad];
}
SDWebImageManager是UIImageView+WebCache的底层实现,通过SDWebImageManager可以实现异步的下载UIImage,官方也给出了示例代码。
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager downloadWithURL:imageURL
options:0
progress:^(NSInteger receivedSize, NSInteger expectedSize)
{
// progression tracking code
}
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished)
{
if (image)
{
// do something with image
}
}];
但是SDWebImageManager并没有提供取消特定任务的方法,想要取消下载任务,会很麻烦。
如果只是希望使用SDWebImageManager实现pregress的效果显示加载进度。UIImageView+WebCache也提供了类似的方法。
[_imageView setImageWithURL:[NSURL URLWithString:url]
placeholderImage:nil
options:0
progress:^(NSInteger receivedSize, NSInteger expectedSize) {
[weakSelf.downloadProgressLabel setText:[NSString stringWithFormat:@"%d%%",(int)(receivedSize*100/expectedSize)]];
}
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {
_downloadProgressLabel.hidden = YES;
}];
正如之前说的,使用[_imageView cancleCurrentImageLoad]可以取消这个ImageView的图片加载。
API 文档地址 http://hackemist.com/SDWebImage/doc/。
#import
...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MyIdentifier = @"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:MyIdentifier] autorelease];
}
// Here we use the new provided setImageWithURL: method to load the web image
[cell.imageView setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"]
placeholderImage:[UIImage imageNamed:@"placeholder.png"]];
cell.textLabel.text = @"My Text";
return cell;
}
// Here we use the new provided setImageWithURL: method to load the web image
[cell.imageView setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"]
placeholderImage:[UIImage imageNamed:@"placeholder.png"]
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {... completion code here ...}];
Using SDWebImageManager
The SDWebImageManager is the class behind the UIImageView+WebCache category. It ties the asynchronous downloader with the image cache store. You can use this class directly to benefit from web image downloading with caching in another context than a UIView (ie: with Cocoa)
下面是如何使用SDWebImageManager的代码:
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager downloadWithURL:imageURL
options:0
progress:^(NSUInteger receivedSize, long long expectedSize)
{
// progression tracking code
}
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType)
{
if (image)
{
// do something with image
}
}];
[SDWebImageDownloader.sharedDownloader downloadImageWithURL:imageURL
options:0
progress:^(NSUInteger receivedSize, long long expectedSize)
{
// progression tracking code
}
completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished)
{
if (image && finished)
{
// do something with image
}
}];
SDImageCache *imageCache = [SDImageCache.alloc initWithNamespace:@"myNamespace"];
[imageCache queryDiskCacheForKey:myCacheKey done:^(UIImage *image)
{
// image is not nil if image was found
}];
[[SDImageCache sharedImageCache] storeImage:myImage forKey:myCacheKey];
SDWebImage的cache有两个,硬盘cache和内存cache. 硬盘cache可以保存已下载的图片,避免再次下载;内存cache可以加速图片的加载速度,减少磁盘I/O.
既然有cache,肯定也有清除cache的方法,SDImageCache提供了清除硬盘cache和内存cache的方法,
[[SDImageCache sharedImageCache]clearDisk];
[[SDImageCache sharedImageCache]clearMemory];
一般情况下,我们并不需要手动的去清理cache,SDImageCache注册了相关的监听器,可以处理这些事宜。
// Subscribe to app events
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(clearMemory)
name:UIApplicationDidReceiveMemoryWarningNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(cleanDisk)
name:UIApplicationWillTerminateNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(backgroundCleanDisk)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
上面的代码可以发现,当收到MemoryWarning时,SDImageCache会自动清空内存中的cache;当程序退出的时候,SDImageCache会clean硬盘上得cache,clean并不是clear,clean会将超出“保质期“的缓存图片删除掉。这个“保质期“可以通过maxCacheAge进行设定:
[SDImageCache sharedImageCache].maxCacheAge = 1 * 24 * 60 * 60; // 1 day
默认的“保质期”时间是:
static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week
与SDImageCache相关的SDImageCacheType定义了加载的image的来源,下面是SDImageCacheType的定义。
typedef NS_ENUM(NSInteger, SDImageCacheType) {
/**
* The image wasn't available the SDWebImage caches, but was downloaded from the web.
*/
SDImageCacheTypeNone,
/**
* The image was obtained from the disk cache.
*/
SDImageCacheTypeDisk,
/**
* The image was obtained from the memory cache.
*/
SDImageCacheTypeMemory
};
如果注意到之前的setImageWithURL:placeholderImage:options:progress:completed:方法,可以发现,completed的block参数包含一个cacheType,这个cacheType便是标记着当前image的来源。如果我们要对每个来自网络的图片进行淡入效果显示,可以这样写:
//other code
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {
_imageView.alpha = 0;
if (cacheType == SDImageCacheTypeNone){
[UIView animateWithDuration:0.3 animations:^{
_imageView.alpha = 1;
}];
}
}];
下面的示例在应用程序的委托中设置一个过滤器,在使用它的缓存键之前将从URL中删除任何查询字符串(The following example sets a filter in the application delegate that will remove any query-string from the URL before to use it as a cache key):
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
SDWebImageManager.sharedManager.cacheKeyFilter:^(NSURL *url)
{
url = [[[NSURL alloc] initWithScheme:url.scheme host:url.host path:url.path] autorelease];
return [url absoluteString];
};
// Your app init code...
return YES;
}
http://www.wrichards.com/blog/2011/11/sdwebimage-fixed-width-cell-images/
如果你不控制你的图像服务器,当它的内容更新时你不能改变它的url。Facebook头像就是这种情况的例子。在这种情况下,你可以使用SDWebImageRefreshCached的标志。这将稍微降低性能,但将会考虑到HTTP缓存控制头:
[imageView setImageWithURL:[NSURL URLWithString:@"https://graph.facebook.com/olivier.poitrey/picture"]
placeholderImage:[UIImage imageNamed:@"avatar-placeholder.png"]
options:SDWebImageRefreshCached];
SDWebImageDecoder只包含一个静态方法:
+ (UIImage *)decodedImageWithImage:(UIImage *)image;
该方法用来对已经加载的UIImage进行解码。
由于UIImage的imageWithData函数是每次画图的时候才将Data解压成ARGB的图像,
所以在每次画图的时候,会有一个解压操作,这样效率很低,但是只有瞬时的内存需求。
为了提高效率通过SDWebImageDecoder将包装在Data下的资源解压,然后画在另外一张图片上,这样这张新图片就不再需要重复解压了。
这种做法是典型的空间换时间的做法。
上面是这段话来自摇滚诗人 http://www.cnblogs.com/biosli/archive/2012/07/21.html
SDWebImage显示Gif很占内存,这和SDWebImage对GIF的解码方式有关,相关代码如下:
+ (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);
duration += [self 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;
}
这里的解码方式,单独对gif的每一帧进行解码,然后加入到animatedImage里面,这样,对于帧数很多的gif,则非常的占用内存。如果对GIF显示并不在乎GIF的显示的话,可以修改size_t count = CGImageSourceGetCount(source); 这段代码为sizt_t count = 1;这样GIF图片只会渲染第一帧,也就变成了一个静态图片展示,内存消耗也变得可以接受的范围。当然,如果要坚持使用GIF动画的话,也可以使用其他的开源项目,有些开源项目可以以占用内存非常少得方式显示GIF动画,比如说VVeboImage.
Open the "Build Settings" tab, in the "Linking" section, locate the "Other Linker Flags" setting and add the "-ObjC" flag:
参考:http://blog.csdn.net/shenjx1225/article/details/10444449
http://www.mzule.com/posts/SDWebImage_usage_experience.html