zoukankan      html  css  js  c++  java
  • iOS

    1、ImageCache

    • 使用内存缓存方式:

      ImageCache1

    • 使用沙盒缓存方式:

      ImageCache2

    • 使用网络图片第三方库方式:

      • 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 <ImageIO/ImageIO.h>                                                 // 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<ObjCBool>) 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 <objc/runtime.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);
        	}
        
      • 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<ObjCBool>) 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 <objc/runtime.h>
        	#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<ObjCBool>) 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
            	}
        
  • 相关阅读:
    SSH的基本操作
    Aptana Studion出现 duplicate location重复定位报错
    centOS6.6虚拟机启动后登陆界面无法显示
    putty的基本使用
    Linux之如何进行固定IP、DNS等设置
    \无法访问。您可能没有权限使用网络资源。请与这台服务器的管理员联系以查明您是否有访问权限。找不到网络路径。解决方法和思路。
    访问共享时提示“你没有权限访问\192.168.0.100共享盘”解决方法?
    ESXI问题汇总
    【亲测】使用U盘安装ESXI6.7全过程以及遇到的问题记录
    U盘安装EXSi6.7出错menu.c32文件
  • 原文地址:https://www.cnblogs.com/QianChia/p/5769305.html
Copyright © 2011-2022 走看看