封装思想之:NSoperation的自定义实现
一 NSoperase自定义封装实现
[以下代码实现来MJ]
实现过程:通过对NSOperation进行自定义的封装,实现自己的功能,这里使用tableView的cell 更新来实现 图片刷新异步操作,节约系统资源优化代码
其中NSOperasion实现先在主线程调用 并添加队列实现异步的操作并在自定义NSOperation中对图片进行加载,完了通过代理实现 返回主线程 进行赋值
一:自定义封装NSOperation
[.h文件实现] HMDownloadOperation.h
该文件主要确定了自定义的需要的数据信息 用于外部接口使用
1 #import <Foundation/Foundation.h> 2 3 @class HMDownloadOperation; 4 5 @protocol HMDownloadOperationDelegate <NSObject> 6 @optional 7 - (void)downloadOperation:(HMDownloadOperation *)operation didFinishDownload:(UIImage *)image; 8 @end 9 10 @interface HMDownloadOperation : NSOperation 11 @property (nonatomic, copy) NSString *url;//用于记录网页中的图片地址 12 @property (nonatomic, strong) NSIndexPath *indexPath;//用来记录cell,当回调时候获取当前要刷新的cell 绑定cell 13 @property (nonatomic, weak) id<HMDownloadOperationDelegate> delegate; 14 @end
[.m文件实现]
在对NSOperation进行封装的时候,m文件必须是现在此操作 实现main函数功能用于实现异步下载,并通过
dispatch_async(dispatch_get_main_queue(), ^{});返回主线程 并刷新UI
1 #import "HMDownloadOperation.h" 2 3 @implementation HMDownloadOperation 4 5 /** 6 * 在main方法中实现具体操作 7 */ 8 - (void)main 9 { 10 @autoreleasepool { 11 12 NSURL *downloadUrl = [NSURL URLWithString:self.url]; 13 NSData *data = [NSData dataWithContentsOfURL:downloadUrl]; // 这行会比较耗时 14 UIImage *image = [UIImage imageWithData:data]; 15 16 if ([self.delegate respondsToSelector:@selector(downloadOperation:didFinishDownload:)]) { 17 dispatch_async(dispatch_get_main_queue(), ^{ // 回到主线程, 传递图片数据给代理对象 18 [self.delegate downloadOperation:self didFinishDownload:image]; 19 }); 20 } 21 } 22 } 23 @end
以下是控制器实现实现【重在实现思路】,tableView刷新cell 将图片的更新与自定义NSOperation相结合,
控制器.m文件的实现
1 #import "HMApp.h" 2 #import "HMViewController.h" 3 #import "HMDownloadOperation.h" 4 5 @interface HMViewController () <HMDownloadOperationDelegate> 6 @property (nonatomic, strong) NSArray *apps; //用来存储数据结构Model 7 @property (nonatomic, strong) NSOperationQueue *queue;//用来全局控制自定义NSOperasion的队列 8 /** key:url value:operation对象 */ 9 @property (nonatomic, strong) NSMutableDictionary *operations; 10 //这里定义一个字典类的操作,是为了实现每一个Cell的Operation与网页中的url地址进行绑定,定义她的字典主要是为了考虑图片正在下载而没有加载到images的情况 11 /** key:url value:image对象*/ 12 @property (nonatomic, strong) NSMutableDictionary *images; 13 //cell中操作的赋值实现,如果对cell进行封装应该都也cell封装类里面 14 @end 15 16 @implementation HMViewController 17 18 - (NSArray *)apps 19 { 20 if (!_apps) { 21 NSArray *dictArray = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"apps.plist" ofType:nil]]; 22 23 NSMutableArray *appArray = [NSMutableArray array]; 24 for (NSDictionary *dict in dictArray) { 25 HMApp *app = [HMApp appWithDict:dict]; 26 [appArray addObject:app]; 27 } 28 _apps = appArray; 29 } 30 return _apps; 31 } 32 33 - (NSOperationQueue *)queue 34 { 35 if (!_queue) { 36 _queue = [[NSOperationQueue alloc] init]; 37 _queue.maxConcurrentOperationCount = 3; // 最大并发数 == 3 38 } 39 return _queue; 40 } 41 42 - (NSMutableDictionary *)operations 43 { 44 if (!_operations) { 45 _operations = [NSMutableDictionary dictionary]; 46 } 47 return _operations; 48 } 49 50 - (NSMutableDictionary *)images 51 { 52 if (!_images) { 53 _images = [NSMutableDictionary dictionary]; 54 } 55 return _images; 56 } 57 58 - (void)viewDidLoad 59 { 60 [super viewDidLoad]; 61 62 } 63 64 #pragma mark - 数据源方法 65 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 66 { 67 return self.apps.count; 68 } 69 70 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 71 { 72 static NSString *ID = @"app"; 73 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; 74 if (!cell) { 75 cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID]; 76 } 77 78 HMApp *app = self.apps[indexPath.row]; 79 cell.textLabel.text = app.name; 80 cell.detailTextLabel.text = app.download; 81 82 // 显示图片 83 // 保证一个url对应一个HMDownloadOperation 84 // 保证一个url对应UIImage对象 85 86 UIImage *image = self.images[app.icon]; 87 if (image) { // 缓存中有图片 88 cell.imageView.image = image; 89 } else { // 缓存中没有图片, 得下载 90 cell.imageView.image = [UIImage imageNamed:@"57437179_42489b0"]; 91 92 HMDownloadOperation *operation = self.operations[app.icon]; 93 if (operation) { // 正在下载 94 // ... 暂时不需要做其他事 95 96 } else { // 没有正在下载 97 // 创建操作 98 operation = [[HMDownloadOperation alloc] init]; 99 operation.url = app.icon; 100 operation.delegate = self; 101 operation.indexPath = indexPath; 102 [self.queue addOperation:operation]; // 异步下载 103 104 self.operations[app.icon] = operation; 105 } 106 } 107 108 // SDWebImage : 专门用来下载图片 109 return cell; 110 } 111 112 #pragma mark - HMDownloadOperationDelegate 113 - (void)downloadOperation:(HMDownloadOperation *)operation didFinishDownload:(UIImage *)image 114 { 115 // 1.移除执行完毕的操作 116 [self.operations removeObjectForKey:operation.url]; 117 118 if (image) { 119 // 2.将图片放到缓存中(images) 120 self.images[operation.url] = image; 121 122 // 3.刷新表格 123 [self.tableView reloadRowsAtIndexPaths:@[operation.indexPath] withRowAnimation:UITableViewRowAnimationNone]; 124 125 // 3.将图片写入沙盒 126 // NSData *data = UIImagePNGRepresentation(image); 127 // [data writeToFile:@"" atomically:<#(BOOL)#>]; 128 } 129 130 } 131 132 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView 133 { 134 // 开始拖拽 135 // 暂停队列 136 [self.queue setSuspended:YES]; 137 } 138 139 - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset 140 { 141 [self.queue setSuspended:NO]; 142 } 143 144 @end