iosimagecache网络图片缓存

yjand615 贡献于2016-11-25

作者 杨十郎  创建于2016-11-08 09:36:00   修改者杨十郎  修改于2016-11-08 09:36:00字数29399

文档摘要:
关键词:

iOS - ImageCache 网络图片缓存 本文目录 · 1、ImageCache · 2、自定义内存缓存方式 · 3、自定义沙盒缓存方式 · 4、仿 SDWebImage 缓存方式 · 5、SDWebImage 缓存方式 回到顶部 1、ImageCache · 使用内存缓存方式: · 使用沙盒缓存方式: · 使用网络图片第三方库方式: · SDWebImage: · iOS 中著名的网络图片处理框架 · 包含的功能:图片下载、图片缓存、下载进度监听、gif 处理等等 · 用法极其简单,功能十分强大,大大提高了网络图片的处理效率 · 国内超过 90% 的 iOS 项目都有它的影子 · 1、图片文件缓存的时间有多长? · 1 周 · _maxCacheAge = kDefaultCacheMaxCacheAge; // - (id)initWithNamespace: diskCacheDirectory: · static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week SDImageCache.m · 2、SDWebImage 的内存缓存是用什么实现的? · NSCache · 3、SDWebImage 的最大并发数是多少? · 是程序固定死了,可以通过属性进行调整! _downloadQueue.maxConcurrentOperationCount = 6; // SDWebImageDownloader.m - (id)init · 4、网络访问超时时长 · iOS 开发中,默认的访问时长是 1 分钟,SDWebImage 中是 15 秒。 _downloadTimeout = 15.0; // SDWebImageDownloader.m - (id)init · 5、SDWebImage 支持动图吗?GIF · 支持 · #import // UIImage+GIF.m [UIImage animatedImageWithImages:images duration:duration]; · 6、SDWebImage 是如何区分不同格式的图像的 · 根据图像数据第一个字节来判断的! · // NSData+ImageContentType.m + (NSString *)sd_contentTypeForImageData: · · PNG:0x89 image/png ,压缩比没有 JPG 高,但是无损压缩,解压缩性能高,苹果推荐的图像格式! · JPG:0xFF image/jpeg,压缩比最高的一种图片格式,有损压缩!最多使用的场景,照相机!解压缩的性能不好! GIF:0x47 image/gif ,序列桢动图,特点:只支持 256 种颜色!最流行的时候在 1998~1999,有专利的! · 7、SDWebImage 缓存图片的名称是怎么确定的! · md5 · 如果单纯使用 文件名保存,重名的几率很高! · 使用 MD5 的散列函数!对完整的 URL 进行 md5,结果是一个 32 个字符长度的字符串! · 8、SDWebImage 的内存警告是如何处理的! · 利用通知中心观察 · UIApplicationDidReceiveMemoryWarningNotification 接收到内存警告的通知 · 执行 clearMemory 方法,清理内存缓存! · UIApplicationWillTerminateNotification 接收到应用程序将要终止通知 · 执行 cleanDisk 方法,清理磁盘缓存! · UIApplicationDidEnterBackgroundNotification 接收到应用程序进入后台通知 · 执行 backgroundCleanDisk 方法,后台清理磁盘! · 通过以上通知监听,能够保证缓存文件的大小始终在控制范围之内! · clearDisk 清空磁盘缓存,将所有缓存目录中的文件,全部删除! 实际工作,将缓存目录直接删除,再次创建一个同名空目录! · bug: · SDWebImage 中,一旦内存警告,清理了内存之后,之后所有的图片都是从沙盒加载的。 · 原因:NSCache 中一旦调用了 removeAllObjects,就无法给 cache 添加对象。关于 NSCache 的内存管理,交给他自己就行! 回到顶部 2、自定义内存缓存方式 · Objective-C · AppInfoModel.h · @interface AppInfoModel : NSObject · · /// 标题名称 · @property (nonatomic, strong) NSString *name; · · /// 下载数量 · @property (nonatomic, strong) NSString *download; · · /// 图片地址 · @property (nonatomic, strong) NSString *icon; · · /// 声明工厂方法,数据源初始化方法 · + (instancetype)appInfoModelWithDict:(NSDictionary *)dict; · @end · AppInfoModel.m · // 实现工厂方法 · + (instancetype)appInfoModelWithDict:(NSDictionary *)dict { · · id obj = [[self alloc] init]; · · [obj setValuesForKeysWithDictionary:dict]; · · return obj; } · AppInfoCell.h · @interface AppInfoCell : UITableViewCell · · @property (nonatomic, weak) IBOutlet UILabel *nameLabel; · @property (nonatomic, weak) IBOutlet UILabel *downloadLabel; · @property (nonatomic, weak) IBOutlet UIImageView *iconImageView; · @end · ViewController.m · /// 表格数据源 · @property (nonatomic, strong) NSArray *dataSourceArray; · · /// 图片下载队列 · @property (nonatomic, strong) NSOperationQueue *downloadQueue; · · /// 下载缓冲池 · @property (nonatomic, strong) NSMutableDictionary *downloadQueueCache; · · /// 图片缓冲池 · @property (nonatomic, strong) NSMutableDictionary *imageCache; · · /// 图片下载地址黑名单 · @property (nonatomic, retain) NSMutableArray *urlBlackList; · · // 懒加载 · · - (NSArray *)dataSourceArray { · if (_dataSourceArray == nil) { · NSArray *array = [NSArray arrayWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"apps.plist" withExtension:nil]]; · · NSMutableArray *arrayM = [NSMutableArray arrayWithCapacity:array.count]; · [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { · [arrayM addObject:[AppInfoModel appInfoModelWithDict:obj]]; · }]; · _dataSourceArray = [arrayM copy]; · } · return _dataSourceArray; · } · · - (NSOperationQueue *)downloadQueue { · if (_downloadQueue == nil) { · _downloadQueue = [[NSOperationQueue alloc] init]; · } · return _downloadQueue; · } · · - (NSMutableDictionary *)downloadQueueCache { · if (_downloadQueueCache == nil) { · _downloadQueueCache = [[NSMutableDictionary alloc] init]; · } · return _downloadQueueCache; · } · · - (NSMutableDictionary *)imageCache { · if (_imageCache == nil) { · _imageCache = [[NSMutableDictionary alloc] init]; · } · return _imageCache; · } · · - (NSMutableArray *)urlBlackList { · if (_urlBlackList == nil) { · _urlBlackList = [[NSMutableArray alloc] init]; · } · return _urlBlackList; · } · · // 表格视图数据源方法 · · - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { · return self.dataSourceArray.count; · } · · - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { · · AppInfoCell *cell = [tableView dequeueReusableCellWithIdentifier:@"AppCell" forIndexPath:indexPath]; · · AppInfoModel *dataModel = self.dataSourceArray[indexPath.row]; · · cell.nameLabel.text = dataModel.name; · cell.downloadLabel.text = dataModel.download; · · // 判断图片缓存池中是否有相应的图片 · if (self.imageCache[dataModel.icon] != nil) { · · // 从缓存池中取出图片显示在 Cell 上 · cell.iconImageView.image = self.imageCache[dataModel.icon]; · } else { · · // 从网络异步下载图片 · [self downloadImageWithIndexPath:indexPath]; · } · · return cell; · } · · - (void)downloadImageWithIndexPath:(NSIndexPath *)indexPath { · AppInfoModel *dataModel = self.dataSourceArray[indexPath.row]; · · // 判断下载缓冲池中是否存在当前下载操作 · if (self.downloadQueueCache[dataModel.icon] != nil) { · return; · } · · // 判断图片地址是否在黑名单中 · if ([self.urlBlackList containsObject:dataModel.icon]) { · return; · } · · // 创建异步下载图片操作 · NSBlockOperation *downloadOperation = [NSBlockOperation blockOperationWithBlock:^{ · · UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:dataModel.icon]]]; · · // 下载完成从下载缓冲池中删除当前下载操作 · [self.downloadQueueCache removeObjectForKey:dataModel.icon]; · · // 添加黑名单记录 · if (image == nil && ![self.urlBlackList containsObject:dataModel.icon]) { · [self.urlBlackList addObject:dataModel.icon]; · } · · // 主线程跟新 UI · [[NSOperationQueue mainQueue] addOperationWithBlock:^{ · · if (image != nil) { · · // 将下载完成的图片保存到图片缓冲池中 · [self.imageCache setObject:image forKey:dataModel.icon]; · · [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; · } · }]; · }]; · · // 将当前下载添加到下载缓冲池中 · [self.downloadQueueCache setObject:downloadOperation forKey:dataModel.icon]; · · // 开始异步下载图片 · [self.downloadQueue addOperation:downloadOperation]; · } · · // 内存警告 · /* · 日常上课通常就直接删除,但是在工作后,必须要处理!不处理后果很严重,第一次内存警告如果不处理,就没有第二次的机会了,就直接被闪退了 · */ · · - (void)didReceiveMemoryWarning { · · [super didReceiveMemoryWarning]; · · // 清理缓冲池 · [self.downloadQueueCache removeAllObjects]; · [self.imageCache removeAllObjects]; · · // 取消下载操作,等用户再滚动表格,调用数据源方法,又能够自动下载 · [self.downloadQueue cancelAllOperations]; } · Swift · AppInfo.swift · class AppInfo: NSObject { · · var name:String! · var icon:String! · var download:String! · · class func AppInfoWithDict(dict:[String:AnyObject]) -> AnyObject { · let obj:AnyObject = self.init() · · obj.setValuesForKeysWithDictionary(dict) · · return obj · } · · required override init() { · super.init() · } } · AppInfoCell.swift · class AppInfoCell: UITableViewCell { · · @IBOutlet weak var iconView: UIImageView! · @IBOutlet weak var nameLabel: UILabel! · @IBOutlet weak var downLabel: UILabel! } · ViewController.swift · // 懒加载 · · // 数据源 · lazy var dataSourceArray:[AnyObject] = { · var dataArray:[AnyObject] = Array() · · let array = NSArray(contentsOfURL: NSBundle.mainBundle().URLForResource("apps.plist", withExtension: nil)!) · array!.enumerateObjectsUsingBlock { (obj:AnyObject, idx:Int, stop:UnsafeMutablePointer) in · dataArray.append(AppInfoModel.AppInfoWithDict(obj as! [String : AnyObject])) · } · return dataArray · }() · · // 下载队列 · lazy var downloadQueue:NSOperationQueue = { · var tmp:NSOperationQueue = NSOperationQueue() · return tmp · }() · · // 下载缓冲池 · lazy var downloadQueueCache:[String:NSBlockOperation] = { · var tmp:[String:NSBlockOperation] = Dictionary() · return tmp · }() · · // 图片缓冲池 · lazy var imageCache:[String:UIImage] = { · var tmp:[String:UIImage] = Dictionary() · return tmp · }() · · // 图片下载地址黑名单 · lazy var urlBlackList:[String] = { · var tmp:[String] = Array() · return tmp · }() · · // 表格视图数据源方法 · · override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { · return self.dataSourceArray.count · } · · override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { · · let cell:AppInfoCell = tableView.dequeueReusableCellWithIdentifier("AppCell", forIndexPath: indexPath) as! AppInfoCell · · let dataModel = self.dataSourceArray[indexPath.row] as! AppInfoModel · · cell.nameLabel.text = dataModel.name · cell.downLabel.text = dataModel.download · · // 判断图片缓存池中是否有相应的图片 · if self.imageCache[dataModel.icon] != nil { · · // 从缓存池中取出图片显示在 Cell 上 · cell.iconView.image = self.imageCache[dataModel.icon] · } else { · · // 从网络异步下载图片 · self.downloadImageWithIndexPath(indexPath) · } · return cell · } · func downloadImageWithIndexPath(indexPath:NSIndexPath) { · · let dataModel = self.dataSourceArray[indexPath.row] as! AppInfoModel · · // 判断下载缓冲池中是否存在当前下载操作 · if self.downloadQueueCache[dataModel.icon] != nil { · return · } · · // 判断图片地址是否在黑名单中 · if self.urlBlackList.contains(dataModel.icon) { · return · } · · // 创建异步下载图片操作 · let downloadOperation = NSBlockOperation { · · let image:UIImage? = UIImage(data: NSData(contentsOfURL: NSURL(string: dataModel.icon)!)!) · · // 下载完成从下载缓冲池中删除当前下载操作 · self.downloadQueueCache.removeValueForKey(dataModel.icon) · · // 添加黑名单记录 · if image == nil && !self.urlBlackList.contains(dataModel.icon) { · · self.urlBlackList.append(dataModel.icon) · } · · // 主线程跟新 UI · NSOperationQueue.mainQueue().addOperationWithBlock({ · if image != nil { · · // 将下载完成的图片保存到图片缓冲池中 · self.imageCache[dataModel.icon] = image · · self.tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic) · } · }) · } · · // 将当前下载添加到下载缓冲池中 · self.downloadQueueCache[dataModel.icon] = downloadOperation · · // 开始异步下载图片 · self.downloadQueue.addOperation(downloadOperation) · } · · // 内存警告 · · override func didReceiveMemoryWarning() { · super.didReceiveMemoryWarning() · · self.downloadQueueCache.removeAll() · self.imageCache.removeAll() · · self.downloadQueue.cancelAllOperations() } 回到顶部 3、自定义沙盒缓存方式 · Objective-C · AppInfoModel.h · AppInfoModel.m · AppInfoCell.h · 与上边一样 · NSString+BundlePath.h · /// 拼接缓存目录 - (NSString *)appendCachePath; · NSString+BundlePath.m · - (NSString *)appendCachePath { · NSString *dir = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).lastObject; · return [dir stringByAppendingPathComponent:self.lastPathComponent]; } · ViewController.m · // 懒加载 · · 与上边一样 · · // 表格视图数据源方法 · · - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { · return self.dataSourceArray.count; · } · - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { · · AppInfoCell *cell = [tableView dequeueReusableCellWithIdentifier:@"AppCell" forIndexPath:indexPath]; · · AppInfoModel *dataModel = self.dataSourceArray[indexPath.row]; · · cell.nameLabel.text = dataModel.name; · cell.downloadLabel.text = dataModel.download; · · // 判断图片缓存池中是否有相应的图片 · if (self.imageCache[dataModel.icon] != nil) { · · // 从缓存池中取出图片显示在 Cell 上 · cell.iconImageView.image = self.imageCache[dataModel.icon]; · } else { · · // 从沙盒加载图片 · UIImage *image = [UIImage imageWithContentsOfFile:[dataModel.icon appendCachePath]]; · · if (image != nil) { · · cell.iconImageView.image = image; · self.imageCache[dataModel.icon] = image; · · } else { · · // 从网络异步下载图片 · [self downloadImageWithIndexPath:indexPath]; · } · } · · return cell; · } · · - (void)downloadImageWithIndexPath:(NSIndexPath *)indexPath { · · AppInfoModel *dataModel = self.dataSourceArray[indexPath.row]; · · // 判断下载缓冲池中是否存在当前下载操作 · if (self.downloadQueueCache[dataModel.icon] != nil) { · return; · } · · // 判断图片地址是否在黑名单中 · if ([self.urlBlackList containsObject:dataModel.icon]) { · · return; · } · · // 创建异步下载图片操作 · NSBlockOperation *downloadOperation = [NSBlockOperation blockOperationWithBlock:^{ · · NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:dataModel.icon]]; · UIImage *image = [UIImage imageWithData:imageData]; · · // 下载完成从下载缓冲池中删除当前下载操作 · [self.downloadQueueCache removeObjectForKey:dataModel.icon]; · · // 添加黑名单记录 · if (image == nil && ![self.urlBlackList containsObject:dataModel.icon]) { · [self.urlBlackList addObject:dataModel.icon]; · } · · if (image != nil) { · · // 将图像写入沙盒 · [imageData writeToFile:[dataModel.icon appendCachePath] atomically:YES]; · } · · // 主线程跟新 UI · [[NSOperationQueue mainQueue] addOperationWithBlock:^{ · · if (image != nil) { · · // 将下载完成的图片保存到图片缓冲池中 · [self.imageCache setObject:image forKey:dataModel.icon]; · · [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; · } · }]; · }]; · · // 将当前下载添加到下载缓冲池中 · [self.downloadQueueCache setObject:downloadOperation forKey:dataModel.icon]; · · // 开始异步下载图片 · [self.downloadQueue addOperation:downloadOperation]; · } · · // 内存警告 · 与上边一样 · Swift · AppInfo.swift · AppInfoCell.swift · 与上边一样 · String+BundlePath.swift · public func appendCachePath() -> String? { · let dir:String? = NSSearchPathForDirectoriesInDomains(.CachesDirectory, .UserDomainMask, true).last · if (dir != nil) { · return dir! + "/" + (self as NSString).lastPathComponent · } else { · return nil · } } · ViewController.swift · // 懒加载 · · 与上边一样 · · // 表格视图数据源方法 · · override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { · return self.dataSourceArray.count · } · · override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { · · let cell:AppInfoCell = tableView.dequeueReusableCellWithIdentifier("AppCell", forIndexPath: indexPath) as! AppInfoCell · · let dataModel = self.dataSourceArray[indexPath.row] as! AppInfoModel · · cell.nameLabel.text = dataModel.name · cell.downLabel.text = dataModel.download · · // 判断图片缓存池中是否有相应的图片 · if self.imageCache[dataModel.icon] != nil { · · // 从缓存池中取出图片显示在 Cell 上 · cell.iconView.image = self.imageCache[dataModel.icon] · · } else { · · // 从沙盒加载图片 · let image = UIImage(contentsOfFile: dataModel.icon.appendCachePath()!) · · if (image != nil) { · · cell.iconView.image = image · self.imageCache[dataModel.icon] = image · · } else { · · // 从网络异步下载图片 · self.downloadImageWithIndexPath(indexPath) · } · } · · return cell · } · · func downloadImageWithIndexPath(indexPath:NSIndexPath) { · · let dataModel = self.dataSourceArray[indexPath.row] as! AppInfoModel · · // 判断下载缓冲池中是否存在当前下载操作 · if self.downloadQueueCache[dataModel.icon] != nil { · · return · } · · // 判断图片地址是否在黑名单中 · if self.urlBlackList.contains(dataModel.icon) { · · return · } · · // 创建异步下载图片操作 · let downloadOperation = NSBlockOperation { · · let imageData:NSData? = NSData(contentsOfURL: NSURL(string: dataModel.icon)!) · · let image:UIImage? = UIImage(data: imageData!) · · // 下载完成从下载缓冲池中删除当前下载操作 · self.downloadQueueCache.removeValueForKey(dataModel.icon) · · // 添加黑名单记录 · if image == nil && !self.urlBlackList.contains(dataModel.icon) { · · self.urlBlackList.append(dataModel.icon) · } · · if image != nil { · · // 将图像写入沙盒 · imageData!.writeToFile(dataModel.icon.appendCachePath()!, atomically: true) · · print(dataModel.icon.appendCachePath()!) · } · · // 主线程跟新 UI · NSOperationQueue.mainQueue().addOperationWithBlock({ · · if image != nil { · · // 将下载完成的图片保存到图片缓冲池中 · self.imageCache[dataModel.icon] = image · · self.tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic) · } · }) · } · · // 将当前下载添加到下载缓冲池中 · self.downloadQueueCache[dataModel.icon] = downloadOperation · · // 开始异步下载图片 · self.downloadQueue.addOperation(downloadOperation) · } · · // 内存警告 · 与上边一样 回到顶部 4、仿 SDWebImage 缓存方式 · Objective-C · AppInfoModel.h · @interface AppInfoModel : NSObject · · /// 标题名称 · @property (nonatomic, strong) NSString *name; · · /// 下载数量 · @property (nonatomic, strong) NSString *download; · · /// 图片地址 · @property (nonatomic, strong) NSString *icon; · · /// 从 Plist 加载 AppInfo · + (NSArray *)loadPList; · @end · AppInfoModel.m · + (NSArray *)loadPList { · NSArray *array = [NSArray arrayWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"apps.plist" withExtension:nil]]; · · NSMutableArray *plist = [NSMutableArray arrayWithCapacity:array.count]; · [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { · · id model = [[self alloc] init]; · [model setValuesForKeysWithDictionary:obj]; · · [plist addObject:model]; · }]; · · return plist; } · AppInfoCell.h · @interface AppInfoCell : UITableViewCell · · @property (nonatomic, weak) IBOutlet UILabel *nameLabel; · @property (nonatomic, weak) IBOutlet UILabel *downloadLabel; · @property (nonatomic, weak) IBOutlet UIImageView *iconImageView; · @end · NSString+BundlePath.h · /// 拼接缓存目录 - (NSString *)appendCachePath; · NSString+BundlePath.m · - (NSString *)appendCachePath { · NSString *dir = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).lastObject; · return [dir stringByAppendingPathComponent:self.lastPathComponent]; } · WebImageOperation.h · @interface WebImageOperation : NSOperation · · /// 实例化 web 图像操作 · + (instancetype)webImageOperationWithURLString:(NSString *)urlString completion:(void (^)(UIImage *image))completion; · @end · WebImageOperation.m · /// 下载图片的 URL · @property (nonatomic, copy) NSString *urlStr; · · /// 下载完成的回调 · @property (nonatomic, copy) void (^completion) (UIImage *image); · · + (instancetype)webImageOperationWithURLString:(NSString *)urlString completion:(void (^)(UIImage *))completion { · · WebImageOperation *imageOperation = [[self alloc] init]; · · imageOperation.urlStr= urlString; · imageOperation.completion = completion; · · return imageOperation; · } · · // 操作加入队列后会自动执行该方法 · - (void)main { · @autoreleasepool { · · if (self.isCancelled) return; · · NSURL *url = [NSURL URLWithString:self.urlStr]; · NSData *data = [NSData dataWithContentsOfURL:url]; · · if (self.isCancelled) return; · · if (data != nil) { · [data writeToFile:self.urlStr.appendCachePath atomically:YES]; · } · · if (self.isCancelled) return; · · if (self.completion && data != nil) { · · [[NSOperationQueue mainQueue] addOperationWithBlock:^{ · · self.completion([UIImage imageWithData:data]); · }]; · } · } } · WebImageManager.h · // 负责所有网络图像的下载操作以及缓存管理! · @interface WebImageManager : NSObject · · /// 全局单例访问入口 · + (instancetype)sharedManager; · · /// 下载网络图像 · - (void)downloadImage:(NSString *)urlString completion:(void (^) (UIImage *image))completion; · · /// 取消 urlString 对应的下载操作 · - (void)cancelDownload:(NSString *)urlString; · @end · WebImageManager.m · /// 下载队列 · @property (nonatomic, strong) NSOperationQueue *downloadQueue; · · /// 下载操作缓冲池 · @property (nonatomic, strong) NSMutableDictionary *downloadQueueCache; · · /// 图片缓冲池 · @property (nonatomic, strong) NSMutableDictionary *imageCache; · · // 下载管理器 · · // 实例化下载管理器 · + (instancetype)sharedManager { · · static id instance; · · static dispatch_once_t onceToken; · dispatch_once(&onceToken, ^{ · instance = [[self alloc] init]; · }); · return instance; · } · · // 下载操作 · - (void)downloadImage:(NSString *)urlString completion:(void (^)(UIImage *))completion { · · // 判断缓存中是否存在图像 · if ([self checkCacheWithURLString:urlString]) { · · if (completion != nil) { · · // 直接回调,传递给调用方图像 · completion(self.imageCache[urlString]); · } · · return; · } · · // 判断缓冲池中是否存在下载操作 · if (self.downloadQueueCache[urlString] != nil) { · · return; · } · · WebImageOperation *downloadOperation = [WebImageOperation webImageOperationWithURLString:urlString · completion:^(UIImage *image) { · · // 下载完成从操作缓冲池中移除操作 · [self.downloadQueueCache removeObjectForKey:urlString]; · · // 下载完成添加到图片缓冲池中 · [self.imageCache setObject:image forKey:urlString]; · · if (completion != nil) { · completion(image); · } · }]; · · // 将操作添加到缓冲池 · [self.downloadQueueCache setObject:downloadOperation forKey:urlString]; · · // 将操作添加到队列 · [self.downloadQueue addOperation:downloadOperation]; · } · · // 取消 urlString 对应的下载操作 · - (void)cancelDownload:(NSString *)urlString { · · // 从缓冲池拿到下载操作 · WebImageOperation *downloadOperation = self.downloadQueueCache[urlString]; · · if (downloadOperation != nil) { · · // 取消操作 · [downloadOperation cancel]; · · // 从缓冲池中删除操作 · [self.downloadQueueCache removeObjectForKey:urlString]; · } · } · · // 判断缓存中是否存在图像 · - (BOOL)checkCacheWithURLString:(NSString *)urlString { · · // 判断图片缓冲池中是否存在图像 · if (self.imageCache[urlString] != nil) { · return YES; · } · UIImage *image = [UIImage imageWithContentsOfFile:[urlString appendCachePath]]; · · // 判断沙盒中是否存在图像 · if (image != nil) { · · [self.imageCache setObject:image forKey:urlString]; · · return YES; · } · · return NO; · } · · // 懒加载 · · - (NSOperationQueue *)downloadQueue { · if (_downloadQueue == nil) { · _downloadQueue = [[NSOperationQueue alloc] init]; · } · return _downloadQueue; · } · · - (NSMutableDictionary *)downloadQueueCache { · if (_downloadQueueCache == nil) { · _downloadQueueCache = [[NSMutableDictionary alloc] init]; · } · return _downloadQueueCache; · } · · - (NSMutableDictionary *)imageCache { · if (_imageCache == nil) { · _imageCache = [[NSMutableDictionary alloc] init]; · } · return _imageCache; } · UIImageView+WebImageView.h · @interface UIImageView (WebImageView) · · /// 设置 Web 图像 URL,自动加载图像 · - (void)setWebImageWithURL:(NSString *)urlString; · @end · UIImageView+WebImageView.m · #import · · // 下载图片的 url · @property (nonatomic, copy) NSString *urlStr; · · - (void)setWebImageWithURL:(NSString *)urlString { · · // 屏蔽快速滑动重复添加下载 · if ([self.urlStr isEqualToString:urlString]) { · · return; · } · · // 暂停之前的操作 · if (self.urlStr != nil && ![self.urlStr isEqualToString:urlString]) { · · [[WebImageManager sharedManager] cancelDownload:self.urlStr]; · · // 如果 ImageView 之前有图像-清空图像 · self.image = nil; · } · · // 记录新的 url · self.urlStr = urlString; · · __weak typeof(self) weakSelf = self; · · // 下载网络图片 · [[WebImageManager sharedManager] downloadImage:self.urlStr completion:^(UIImage *image) { · weakSelf.image = image; · }]; · } · · // 向分类添加属性 · · // 运行时的关联对象,动态添加属性 · const void *URLStrKey = "URLStrKey"; · · - (void)setUrlStr:(NSString *)urlString { · objc_setAssociatedObject(self, URLStrKey, urlString, OBJC_ASSOCIATION_COPY_NONATOMIC); · } · · - (NSString *)urlStr { · return objc_getAssociatedObject(self, URLStrKey); } · ViewController.m · /// 表格数据源 · @property (nonatomic, strong) NSArray *dataSourceArray; · · // 懒加载 · · - (NSArray *)dataSourceArray { · if (_dataSourceArray == nil) { · _dataSourceArray = [AppInfoModel loadPList]; · } · return _dataSourceArray; · } · · // 表格视图数据源方法 · · - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { · return self.dataSourceArray.count; · } · · - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { · · AppInfoCell *cell = [tableView dequeueReusableCellWithIdentifier:@"AppCell" forIndexPath:indexPath]; · · AppInfoModel *dataModel = self.dataSourceArray[indexPath.row]; · · cell.nameLabel.text = dataModel.name; · cell.downloadLabel.text = dataModel.download; · · [cell.iconImageView setWebImageWithURL:dataModel.icon]; · · return cell; } · Swift · AppInfoModel.swift · class AppInfoModel: NSObject · · var name:String! · var icon:String! · var download:String! · class func loadPList() -> [AnyObject] { · let array = NSArray(contentsOfURL: NSBundle.mainBundle().URLForResource("apps.plist", withExtension: nil)!) · · var plist:[AnyObject] = Array() · array!.enumerateObjectsUsingBlock { (obj:AnyObject, idx:Int, stop:UnsafeMutablePointer) in · · let model:AnyObject = self.init() · · model.setValuesForKeysWithDictionary(obj as! [String : AnyObject]) · · plist.append(model) · } · return plist · } · · class func AppInfoWithDict(dict:[String:AnyObject]) -> AnyObject { · let obj:AnyObject = self.init() · · obj.setValuesForKeysWithDictionary(dict) · · return obj · } · · required override init() { · super.init() } · AppInfoCell.swift · @IBOutlet weak var iconView: UIImageView! · @IBOutlet weak var nameLabel: UILabel! @IBOutlet weak var downLabel: UILabel! · String+BundlePath.swift · /// 拼接缓存目录 · public func appendCachePath() -> String? { · let dir:String? = NSSearchPathForDirectoriesInDomains(.CachesDirectory, .UserDomainMask, true).last · if (dir != nil) { · return dir! + "/" + (self as NSString).lastPathComponent · } else { · return nil · } } · WebImageOperation.swift · class WebImageOperation: NSOperation · · /// 下载图片的 URL · var urlStr:String! · · /// 下载完成的回调 · var completion:((image:UIImage) -> Void)! · · class func webImageOperationWithURLString(urlString:String, completion:((image:UIImage) -> Void)) -> WebImageOperation { · · let imageOperation:WebImageOperation = WebImageOperation() · · imageOperation.urlStr = urlString · imageOperation.completion = completion · · return imageOperation · } · · // 操作加入队列后会自动执行该方法 · override func main() { · · if self.cancelled == true { · return · } · · let url:NSURL = NSURL(string: self.urlStr)! · let data:NSData? = NSData(contentsOfURL: url) · · if self.cancelled == true { · return · } · · if data != nil { · · data?.writeToFile(self.urlStr.appendCachePath()!, atomically: true) · } · · if self.cancelled == true { · return · } · · if (self.completion != nil) && (data != nil) { · · NSOperationQueue.mainQueue().addOperationWithBlock({ · · self.completion(image: UIImage(data: data!)!) · }) · } } · WebImageManager.swift · // 负责所有网络图像的下载操作以及缓存管理! · class WebImageManager: NSObject · // 下载队列 · lazy var downloadQueue:NSOperationQueue = { · · var tmp:NSOperationQueue = NSOperationQueue() · return tmp · }() · · // 下载缓冲池 · lazy var downloadQueueCache:[String:WebImageOperation] = { · · var tmp:[String:WebImageOperation] = Dictionary() · return tmp · }() · · // 图片缓冲池 · lazy var imageCache:[String:UIImage] = { · · var tmp:[String:UIImage] = Dictionary() · return tmp · }() · · // 下载管理器 · · static let sharedManager = WebImageManager() · private override init() {} · · // 下载操作 · · func downloadImage(urlString:String, completion:((image:UIImage) -> Void)?) { · · // 判断缓存中是否存在图像 · if self.checkCacheWithURLString(urlString) == true { · · if completion != nil { · · // 直接回调,传递给调用方图像 · completion!(image: self.imageCache[urlString]!) · } · · return · } · · // 判断缓冲池中是否存在下载操作 · if self.downloadQueueCache[urlString] != nil { · · print("玩命下载中...稍安勿躁!") · · return · } · · let downloadOperation:WebImageOperation = WebImageOperation.webImageOperationWithURLString(urlString) { (image) in · · // 下载完成从操作缓冲池中移除操作 · self.downloadQueueCache.removeValueForKey(urlString) · · // 下载完成添加到图片缓冲池中 · self.imageCache[urlString] = image · · if (completion != nil) { · completion!(image: image); · } · } · · // 将操作添加到缓冲池 · self.downloadQueueCache[urlString] = downloadOperation · · // 将操作添加到队列 · self.downloadQueue.addOperation(downloadOperation) · } · · // 取消 urlString 对应的下载操作 · func cancelDownload(urlString:String) { · · // 从缓冲池拿到下载操作 · let downloadOperation:WebImageOperation? = self.downloadQueueCache[urlString] · · if downloadOperation != nil { · · print("取消下载操作") · · // 取消操作 · downloadOperation!.cancel() · · // 从缓冲池中删除操作 · self.downloadQueueCache.removeValueForKey(urlString) · } · } · · // 判断缓存中是否存在图像 · func checkCacheWithURLString(urlString:String) -> Bool { · · // 判断图片缓冲池中是否存在图像 · if self.imageCache[urlString] != nil { · · print("从内存中加载...") · · return true · } · · let image:UIImage? = UIImage(contentsOfFile: urlString.appendCachePath()!) · · // 判断沙盒中是否存在图像 · if image != nil { · · print("从沙盒中加载...") · · self.imageCache[urlString] = image · · return true · } · · return false } · UIImageView+WebImageView.h · @interface UIImageView (WebImageView) · · /// 设置 Web 图像 URL,自动加载图像 · - (void)setWebImageWithURL:(NSString *)urlString; · @end · UIImageView+WebImageView.m · #import · #import "SwiftImageCache-Swift.h" · · // 下载图片的 url · @property (nonatomic, copy) NSString *urlStr; · · - (void)setWebImageWithURL:(NSString *)urlString { · · // 屏蔽快速滑动重复添加下载 · if ([self.urlStr isEqualToString:urlString]) { · · return; · } · · // 暂停之前的操作 · if (self.urlStr != nil && ![self.urlStr isEqualToString:urlString]) { · · [[WebImageManager sharedManager] cancelDownload:self.urlStr]; · · // 如果 ImageView 之前有图像-清空图像 · self.image = nil; · } · · // 记录新的 url · self.urlStr = urlString; · · __weak typeof(self) weakSelf = self; · · // 下载网络图片 · [[WebImageManager sharedManager] downloadImage:self.urlStr completion:^(UIImage *image) { · weakSelf.image = image; · }]; · } · · // 向分类添加属性 · · // 运行时的关联对象,动态添加属性 · const void *URLStrKey = "URLStrKey"; · · - (void)setUrlStr:(NSString *)urlString { · objc_setAssociatedObject(self, URLStrKey, urlString, OBJC_ASSOCIATION_COPY_NONATOMIC); · } · · - (NSString *)urlStr { · return objc_getAssociatedObject(self, URLStrKey); } · SwiftImageCache-Bridging-Header.h #import "UIImageView+WebImageView.h" · ViewController.swift · // 懒加载 · · lazy var dataSourceArray:[AnyObject] = { · var tmp:[AnyObject] = AppInfoModel.loadPList() · return tmp · }() · · // 表格视图数据源方法 · · override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { · return self.dataSourceArray.count · } · · override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { · · let cell:AppInfoCell = tableView.dequeueReusableCellWithIdentifier("AppCell", forIndexPath: indexPath) as! AppInfoCell · · let dataModel = self.dataSourceArray[indexPath.row] as! AppInfoModel · · cell.nameLabel.text = dataModel.name · cell.downLabel.text = dataModel.download · · cell.iconView.setWebImageWithURL(dataModel.icon) · · return cell } 回到顶部 5、SDWebImage 缓存方式 · Github 网址:https://github.com/rs/SDWebImage · SDWebImage 使用 ARC · Objective-C · // 添加第三方库文件 · SDWebImage · · // 包含头文件 #import "UIImageView+WebCache.h" · AppInfoModel.h · @interface AppInfoModel : NSObject · · /// 标题名称 · @property (nonatomic, strong) NSString *name; · · /// 下载数量 · @property (nonatomic, strong) NSString *download; · · /// 图片地址 · @property (nonatomic, strong) NSString *icon; · · /// 从 Plist 加载 AppInfo · + (NSArray *)loadPList; · @end · AppInfoModel.m · + (NSArray *)loadPList { · NSArray *array = [NSArray arrayWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"apps.plist" withExtension:nil]]; · · NSMutableArray *plist = [NSMutableArray arrayWithCapacity:array.count]; · [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { · · id model = [[self alloc] init]; · [model setValuesForKeysWithDictionary:obj]; · · [plist addObject:model]; · }]; · · return plist; } · AppInfoCell.h · @interface AppInfoCell : UITableViewCell · · @property (nonatomic, weak) IBOutlet UILabel *nameLabel; · @property (nonatomic, weak) IBOutlet UILabel *downloadLabel; · @property (nonatomic, weak) IBOutlet UIImageView *iconImageView; · @end · ViewController.m · /// 表格数据源 · @property (nonatomic, strong) NSArray *dataSourceArray; · · // 懒加载 · · - (NSArray *)dataSourceArray { · if (_dataSourceArray == nil) { · _dataSourceArray = [AppInfoModel loadPList]; · } · return _dataSourceArray; · } · · // 表格视图数据源方法 · · - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { · return self.dataSourceArray.count; · } · · - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { · · AppInfoCell *cell = [tableView dequeueReusableCellWithIdentifier:@"AppCell" forIndexPath:indexPath]; · · AppInfoModel *dataModel = self.dataSourceArray[indexPath.row]; · · cell.nameLabel.text = dataModel.name; · cell.downloadLabel.text = dataModel.download; · · [cell.iconImageView sd_setImageWithURL:[NSURL URLWithString:dataModel.icon]]; · · return cell; } · Swift · // 添加第三方库文件 · SDWebImage · · // 创建桥接头文件,如 · SwiftImageCache-Bridging-Header.h · · // 在桥接头文件中添加头文件 #import "UIImageView+WebCache.h" · AppInfoModel.swift · class AppInfoModel: NSObject · · var name:String! · var icon:String! · var download:String! · · class func loadPList() -> [AnyObject] { · let array = NSArray(contentsOfURL: NSBundle.mainBundle().URLForResource("apps.plist", withExtension: nil)!) · · var plist:[AnyObject] = Array() · array!.enumerateObjectsUsingBlock { (obj:AnyObject, idx:Int, stop:UnsafeMutablePointer) in · · let model:AnyObject = self.init() · · model.setValuesForKeysWithDictionary(obj as! [String : AnyObject]) · · plist.append(model) · } · return plist · } · · class func AppInfoWithDict(dict:[String:AnyObject]) -> AnyObject { · let obj:AnyObject = self.init() · · obj.setValuesForKeysWithDictionary(dict) · · return obj · } · · required override init() { · super.init() } · AppInfoCell.swift · class AppInfoCell: UITableViewCell · · @IBOutlet weak var iconView: UIImageView! · @IBOutlet weak var nameLabel: UILabel! @IBOutlet weak var downLabel: UILabel! · ViewController.swift · // 懒加载 · · lazy var dataSourceArray:[AnyObject] = { · var tmp:[AnyObject] = AppInfoModel.loadPList() · return tmp · }() · · // 表格视图数据源方法 · · override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { · return self.dataSourceArray.count · } · · override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { · · let cell:AppInfoCell = tableView.dequeueReusableCellWithIdentifier("AppCell", forIndexPath: indexPath) as! AppInfoCell · let dataModel = self.dataSourceArray[indexPath.row] as! AppInfoModel · · cell.nameLabel.text = dataModel.name · cell.downLabel.text = dataModel.download · · // 设置图片 · cell.iconView.sd_setImageWithURL(NSURL(string: dataModel.icon)) · · return cell }

下载文档到电脑,查找使用更方便

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 10 金币 [ 分享文档获得金币 ] 0 人已下载

下载文档