轉載自 http://www.cnblogs.com/wendingding/p/3811121.html html
1、實現一個簡單的tableView顯示效果緩存
實現效果展現:併發
代碼示例(使用之前在主控制器中進行業務處理的方式)app
1.新建一個項目,讓控制器繼承自UITableViewController。異步
// // YYViewController.h // 01-自定義Operation // // Created by apple on 14-6-26. // Copyright (c) 2014年 itcase. All rights reserved. // #import <UIKit/UIKit.h> @interface YYViewController : UITableViewController @end
2.處理storyboard中得界面,以下:async
3.根據plist文件,字典轉模型ide
新建一個類,繼承自NSObject,做爲數據的模型atom
YYappModel.h文件url
// // YYappModel.h // 01-自定義Operation // // Created by apple on 14-6-26. // Copyright (c) 2014年 itcase. All rights reserved. // #import <Foundation/Foundation.h> @interface YYappModel : NSObject /** *應用名稱 */ @property(nonatomic,copy)NSString *name; /** * 應用圖片 */ @property(nonatomic,copy)NSString *icon; /** * 應用的下載量 */ @property(nonatomic,copy)NSString *download; +(instancetype)appModelWithDict:(NSDictionary *)dict; -(instancetype)initWithDict:(NSDictionary *)dict; @end
YYappModel.m文件spa
// // YYappModel.m // 01-自定義Operation // // Created by apple on 14-6-26. // Copyright (c) 2014年 itcase. All rights reserved. // #import "YYappModel.h" @implementation YYappModel -(instancetype)initWithDict:(NSDictionary *)dict { if (self=[super init]) { [self setValuesForKeysWithDictionary:dict]; } return self; } //工廠方法 +(instancetype)appModelWithDict:(NSDictionary *)dict { return [[self alloc]initWithDict:dict]; } @end
主控制器中得邏輯控制部分,YYViewController.m文件
// // YYViewController.m // 01-自定義Operation // // Created by apple on 14-6-26. // Copyright (c) 2014年 itcase. All rights reserved. // #import "YYViewController.h" #import "YYappModel.h" @interface YYViewController () @property(nonatomic,strong)NSArray *apps; @end @implementation YYViewController #pragma mark- 懶加載 -(NSArray *)apps { if (_apps==nil) { NSString *path=[[NSBundle mainBundle]pathForResource:@"apps.plist" ofType:nil]; NSArray *tempArray=[NSArray arrayWithContentsOfFile:path]; //字典轉模型 NSMutableArray *array=[NSMutableArray array]; for (NSDictionary *dict in tempArray) { YYappModel *app=[YYappModel appModelWithDict:dict]; [array addObject:app]; } _apps=array; } return _apps; } #pragma mark-數據源方法 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.apps.count; } -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *ID=@"ID"; UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:ID]; if (cell==nil) { cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID]; } YYappModel *app=self.apps[indexPath.row]; cell.textLabel.text=app.name; cell.detailTextLabel.text=app.download; //下載圖片數據 NSLog(@"加載圖片數據---%@", [NSThread currentThread]); NSURL *url=[NSURL URLWithString:app.icon]; NSData *data=[NSData dataWithContentsOfURL:url]; UIImage *imgae=[UIImage p_w_picpathWithData:data]; cell.p_w_picpathView.p_w_picpath=imgae; NSLog(@"完成顯示"); return cell; } @end
打印查看:
2、自定義NSOperation
說明:上面的下載圖片數據部分是一個很是耗時的操做,這個操做任務在主線程完成,會嚴重的影響到用戶體驗,形成UI卡的現象。下面經過自定義NSOperation,新開線程,讓加載圖片的任務異步執行。
1.經過代理
在上面的基礎上,新建一個類,讓其繼承自NSOperation。
YYdownLoadOperation.h文件
// // YYdownLoadOperation.h // 01-自定義Operation // // Created by apple on 14-6-26. // Copyright (c) 2014年 itcase. All rights reserved. // #import <Foundation/Foundation.h> #pragma mark-設置代理和代理方法 @class YYdownLoadOperation; @protocol YYdownLoadOperationDelegate <NSObject> -(void)downLoadOperation:(YYdownLoadOperation*)operation didFishedDownLoad:(UIImage *)p_w_picpath; @end @interface YYdownLoadOperation : NSOperation @property(nonatomic,copy)NSString *url; @property(nonatomic,strong)NSIndexPath *indexPath; @property(nonatomic,strong)id <YYdownLoadOperationDelegate> delegate; @end
YYdownLoadOperation.m文件
// // YYdownLoadOperation.m // 01-自定義Operation // // Created by apple on 14-6-26. // Copyright (c) 2014年 itcase. All rights reserved. // #import "YYdownLoadOperation.h" @implementation YYdownLoadOperation -(void)main { NSURL *url=[NSURL URLWithString:self.url]; NSData *data=[NSData dataWithContentsOfURL:url]; UIImage *imgae=[UIImage p_w_picpathWithData:data]; NSLog(@"--%@--",[NSThread currentThread]); //圖片下載完畢後,通知代理 if ([self.delegate respondsToSelector:@selector(downLoadOperation:didFishedDownLoad:)]) { dispatch_async(dispatch_get_main_queue(), ^{//回到主線程,傳遞數據給代理對象 [self.delegate downLoadOperation:self didFishedDownLoad:imgae]; }); } } @end
主控制器中的業務邏輯:
// // YYViewController.m // 01-自定義Operation // // Created by apple on 14-6-26. // Copyright (c) 2014年 itcase. All rights reserved. // #import "YYViewController.h" #import "YYappModel.h" #import "YYdownLoadOperation.h" @interface YYViewController ()<YYdownLoadOperationDelegate> @property(nonatomic,strong)NSArray *apps; @property(nonatomic,strong)NSOperationQueue *queue; @end @implementation YYViewController #pragma mark- 懶加載apps -(NSArray *)apps { if (_apps==nil) { NSString *path=[[NSBundle mainBundle]pathForResource:@"apps.plist" ofType:nil]; NSArray *tempArray=[NSArray arrayWithContentsOfFile:path]; //字典轉模型 NSMutableArray *array=[NSMutableArray array]; for (NSDictionary *dict in tempArray) { YYappModel *app=[YYappModel appModelWithDict:dict]; [array addObject:app]; } _apps=array; } return _apps; } #pragma mark-懶加載queue -(NSOperationQueue *)queue { if (_queue==Nil) { _queue=[[NSOperationQueue alloc]init]; //設置最大併發數爲3 _queue.maxConcurrentOperationCount=3; } return _queue; } #pragma mark-數據源方法 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.apps.count; } -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *ID=@"ID"; UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:ID]; if (cell==nil) { cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID]; } YYappModel *app=self.apps[indexPath.row]; cell.textLabel.text=app.name; cell.detailTextLabel.text=app.download; //下載圖片數據 // NSLog(@"加載圖片數據---%@", [NSThread currentThread]); // NSURL *url=[NSURL URLWithString:app.icon]; // NSData *data=[NSData dataWithContentsOfURL:url]; // UIImage *imgae=[UIImage p_w_picpathWithData:data]; // cell.p_w_picpathView.p_w_picpath=imgae; //建立一個OPeration對象 YYdownLoadOperation *operation=[[YYdownLoadOperation alloc]init]; operation.url=app.icon; operation.indexPath=indexPath; operation.delegate=self; //把操做對象添加到隊列中在去 [self.queue addOperation:operation]; // NSLog(@"完成顯示"); return cell; } -(void)downLoadOperation:(YYdownLoadOperation *)operation didFishedDownLoad:(UIImage *)p_w_picpath { //返回圖片數據給每行對應的cell的p_w_picpathview.p_w_picpath //取出tableview中indexPath這一行對應的cell UITableViewCell *cell=[self.tableView cellForRowAtIndexPath:operation.indexPath]; //顯示圖片 cell.p_w_picpathView.p_w_picpath=p_w_picpath; // NSLog(@"cell--index--%@---%@",operation.indexPath,[NSThread currentThread]); //必定要刷新表格 [self.tableView reloadData]; NSLog(@"--%@--",[NSThread currentThread]); } @end
說明:經過打印能夠發現上面的代碼存在很大的問題。
問題1:須要保證一個url對應一個operation對象。
問題2:下載完須要移除。移除執行完畢的操做。
問題3:保證一個url對應一個p_w_picpath。
下面對主控制器中得代碼進行改進:
// // YYViewController.m // 01-自定義Operation // // Created by apple on 14-6-26. // Copyright (c) 2014年 itcase. All rights reserved. // #import "YYViewController.h" #import "YYappModel.h" #import "YYdownLoadOperation.h" @interface YYViewController ()<YYdownLoadOperationDelegate> @property(nonatomic,strong)NSArray *apps; @property(nonatomic,strong)NSOperationQueue *queue; @property(nonatomic,strong)NSMutableDictionary *operations; @property(nonatomic,strong)NSMutableDictionary *p_w_picpaths; @end @implementation YYViewController #pragma mark- 懶加載apps -(NSArray *)apps { if (_apps==nil) { NSString *path=[[NSBundle mainBundle]pathForResource:@"apps.plist" ofType:nil]; NSArray *tempArray=[NSArray arrayWithContentsOfFile:path]; //字典轉模型 NSMutableArray *array=[NSMutableArray array]; for (NSDictionary *dict in tempArray) { YYappModel *app=[YYappModel appModelWithDict:dict]; [array addObject:app]; } _apps=array; } return _apps; } #pragma mark-懶加載queue -(NSOperationQueue *)queue { if (_queue==Nil) { _queue=[[NSOperationQueue alloc]init]; //設置最大併發數爲3 _queue.maxConcurrentOperationCount=3; } return _queue; } #pragma mark-懶加載operations -(NSMutableDictionary *)operations { if (_operations==Nil) { _operations=[NSMutableDictionary dictionary]; } return _operations; } #pragma mark-懶加載p_w_picpaths -(NSMutableDictionary *)p_w_picpaths { if (_p_w_picpaths==Nil) { _p_w_picpaths=[NSMutableDictionary dictionary]; } return _p_w_picpaths; } #pragma mark-數據源方法 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.apps.count; } -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *ID=@"ID"; UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:ID]; if (cell==nil) { cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID]; } YYappModel *app=self.apps[indexPath.row]; cell.textLabel.text=app.name; cell.detailTextLabel.text=app.download; //保證一個url對應一個p_w_picpath對象 UIImage *p_w_picpath=self.p_w_picpaths[app.icon]; if (p_w_picpath) {//緩存中有圖片 cell.p_w_picpathView.p_w_picpath=p_w_picpath; }else // 緩存中沒有圖片,得下載 { //先設置一張佔位圖片 cell.p_w_picpathView.p_w_picpath=[UIImage p_w_picpathNamed:@"57437179_42489b0"]; YYdownLoadOperation *operation=self.operations[app.icon]; if (operation) {//正在下載 //什麼都不作 }else //當前沒有下載,那就建立操做 { operation=[[YYdownLoadOperation alloc]init]; operation.url=app.icon; operation.indexPath=indexPath; operation.delegate=self; [self.queue addOperation:operation];//異步下載 self.operations[app.icon]=operation; } } return cell; } -(void)downLoadOperation:(YYdownLoadOperation *)operation didFishedDownLoad:(UIImage *)p_w_picpath { //1.移除執行完畢的操做 [self.operations removeObjectForKey:operation.url]; //2.將圖片放到緩存中 self.p_w_picpaths[operation.url]=p_w_picpath; //3.刷新表格(只刷新下載的那一行) [self.tableView reloadRowsAtIndexPaths:@[operation.indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; NSLog(@"--%d--%@--",operation.indexPath.row,[NSThread currentThread]); } @end
打印查看: