一、基础用法

  1 //
  2 //  ViewController.m
  3 //  IOS_0120_NSOperation
  4 //
  5 //  Created by ma c on 16/1/20.
  6 //  Copyright © 2016年 博文科技. All rights reserved.
  7 //
  8
  9 #import "ViewController.h"
 10
 11 @interface ViewController ()<UITableViewDelegate>
 12
 13 @property (nonatomic, strong) UIImageView *imageView;
 14
 15 @end
 16
 17 @implementation ViewController
 18 /*
 19  一、简介
 20  1.NSOperation的作用
 21  配合使用NSOperation和NSOperationQueue也能实现多线程编程
 22
 23  2.NSOperation和NSOperationQueue实现多线程的具体步骤
 24  1>先将需要执行的操作封装到一个NSOperation对象中
 25  2>然后将NSOperation对象添加到NSOperationQueue中
 26  3>系统会自动将NSOperationQueue中的NSOperation取出来
 27  4>将取出的NSOperation封装的操作放到一条新线程中执行
 28
 29  二、NSOperation的子类
 30  1.NSOperation是个抽象类,并不具备封装操作的能力,必须使用它的子类
 31
 32  2.使用NSOperation子类的方式有3种
 33  1>NSInvocationOperation
 34  2>NSBlockOperation
 35  3>自定义子类继承NSOperation,实现内部相应的方法
 36
 37  三、具体使用
 38  1.NSInvocationOperation
 39  1>创建NSInvocationOperation对象
 40  - (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg;
 41
 42  2>调用start方法开始执行操作
 43  - (void)start;
 44  一旦执行操作,就会调用target的sel方法
 45
 46  3>注意
 47  默认情况下,调用了start方法后并不会开一条新线程去执行操作,而是在当前线程同步执行操作
 48  只有将NSOperation放到一个NSOperationQueue中,才会异步执行操作
 49
 50  2.NSBlockOperation
 51  1>创建NSBlockOperation对象
 52  + (id)blockOperationWithBlock:(void (^)(void))block;
 53
 54  2>通过addExecutionBlock:方法添加更多的操作
 55  - (void)addExecutionBlock:(void (^)(void))block;
 56
 57  3>注意:只要NSBlockOperation封装的操作数 > 1,就会异步执行操作
 58
 59 三、NSOperationQueue
 60  1.NSOperationQueue的作用
 61  NSOperation可以调用start方法来执行任务,但默认是同步执行的
 62  如果将NSOperation添加到NSOperationQueue(操作队列)中,系统会自动异步执行NSOperation中的操作
 63
 64  2.添加操作到NSOperationQueue中
 65  - (void)addOperation:(NSOperation *)op;
 66  - (void)addOperationWithBlock:(void (^)(void))block;
 67
 68  四、最大并发数
 69  1.什么是并发数
 70  同时执行的任务数
 71  比如,同时开3个线程执行3个任务,并发数就是3
 72
 73  2.最大并发数的相关方法
 74  - (NSInteger)maxConcurrentOperationCount;
 75  - (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
 76
 77  五、队列的取消、暂停、恢复
 78  取消队列的所有操作
 79  - (void)cancelAllOperations;
 80  提示:也可以调用NSOperation的- (void)cancel方法取消单个操作
 81
 82  暂停和恢复队列
 83  - (void)setSuspended:(BOOL)b; // YES代表暂停队列,NO代表恢复队列
 84  - (BOOL)isSuspended;
 85
 86  六、操作优先级
 87  1.设置NSOperation在queue中的优先级,可以改变操作的执行优先级
 88  - (NSOperationQueuePriority)queuePriority;
 89  - (void)setQueuePriority:(NSOperationQueuePriority)p;
 90
 91  2.优先级的取值
 92  NSOperationQueuePriorityVeryLow = -8L,
 93  NSOperationQueuePriorityLow = -4L,
 94  NSOperationQueuePriorityNormal = 0,
 95  NSOperationQueuePriorityHigh = 4,
 96  NSOperationQueuePriorityVeryHigh = 8
 97
 98  七、操作的监听
 99  1.可以监听一个操作的执行完毕
100  - (void (^)(void))completionBlock;
101  - (void)setCompletionBlock:(void (^)(void))block;
102
103  八、操作的依赖
104  NSOperation之间可以设置依赖来保证执行顺序
105  比如一定要让操作A执行完后,才能执行操作B,可以这么写
106  [operationB addDependency:operationA]; // 操作B依赖于操作A
107  可以在不同queue的NSOperation之间创建依赖关系
108
109  注意:不能相互依赖 比如A依赖B,B依赖A
110
111  九、第三方框架的使用建议
112  1.用第三方框架的目的
113  1> 开发效率:快速开发,人家封装好的一行代码顶自己写的N行
114  2> 为了使用这个功能最牛逼的实现
115
116  2.第三方框架过多,很多坏处(忽略不计)
117  1> 管理、升级、更新
118  2> 第三方框架有BUG,等待作者解决
119  3> 第三方框架的作者不幸去世、停止更新(潜在的BUG无人解决)
120  4> 感觉:自己好水
121
122  3.比如
123  流媒体:播放在线视频、音频(边下载边播放)
124  非常了解音频、视频文件的格式
125  每一种视频都有自己的解码方式(C\C++)
126
127  4.总结
128  1> 站在巨人的肩膀上编程
129  2> 没有关系,使劲用那么比较稳定的第三方框架
130
131 十、SDWebImage
132  1.什么是SDWebImage
133  iOS中著名的牛逼的网络图片处理框架
134  包含的功能:图片下载、图片缓存、下载进度监听、gif处理等等
135  用法极其简单,功能十分强大,大大提高了网络图片的处理效率
136  国内超过90%的iOS项目都有它的影子
137  2.项目地址
138  https://github.com/rs/SDWebImage
139
140  1> 常用方法
141  - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder;
142  - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options;
143  - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletionBlock)completedBlock;
144  - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock;
145
146  2> 内存处理:当app接收到内存警告时
147  当app接收到内存警告
148  - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
149  {
150  SDWebImageManager *mgr = [SDWebImageManager sharedManager];
151
152  // 1.取消正在下载的操作
153  [mgr cancelAll];
154
155  // 2.清除内存缓存
156  [mgr.imageCache clearMemory];
157  }
158  3> SDWebImageOptions
159  * SDWebImageRetryFailed : 下载失败后,会自动重新下载
160  * SDWebImageLowPriority : 当正在进行UI交互时,自动暂停内部的一些下载操作
161  * SDWebImageRetryFailed | SDWebImageLowPriority : 拥有上面2个功能
162
163  十一、自定义NSOperation
164  自定义NSOperation的步骤很简单
165  重写- (void)main方法,在里面实现想执行的任务
166
167  重写- (void)main方法的注意点
168  自己创建自动释放池(因为如果是异步操作,无法访问主线程的自动释放池)
169  经常通过- (BOOL)isCancelled方法检测操作是否被取消,对取消做出响应
170
171  */
172
173 - (void)viewDidLoad {
174     [super viewDidLoad];
175
176 //    [self useNSInvocationOperation];
177 //    [self useBaseNSBlockOperation];
178 //    [self useNSBlockOperation];
179 //    [self useNSOperationQueue];
180 //    [self useAddDependency];
181
182     self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(30, 200, 340, 200)];
183     [self.view addSubview:self.imageView];
184     [self communicate];
185
186 }
187
188 #pragma mark - 通讯
189 - (void)communicate
190 {
191     NSOperationQueue *queue = [[NSOperationQueue alloc] init];
192     //取消队列所有操作
193 //    [queue cancelAllOperations];
194 //    NSLog(@"didCancelAllOperations");
195     //暂停队列
196     [queue setSuspended:YES];
197     //恢复队列
198     [queue setSuspended:NO];
199     //异步下载图片
200     [queue addOperationWithBlock:^{
201         NSURL *url = [NSURL URLWithString:@"http://images.haiwainet.cn/2016/0113/20160113015030150.jpg"];
202         NSData *data = [[NSData alloc] initWithContentsOfURL:url];
203         UIImage *image = [UIImage imageWithData:data];
204         //回到主线程,显示图片
205         [[NSOperationQueue mainQueue] addOperationWithBlock:^{
206             self.imageView.image = image;
207         }];
208     }];
209 }
210
211 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
212 {
213 //    [queue setSuspended:YES]; //暂停队列中所有任务
214 }
215
216 - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
217 {
218 //    [queue setSuspended:NO]; //恢复队列中所有任务
219 }
220
221 #pragma mark - 依赖
222 - (void)useAddDependency
223 {
224     /*三个异步执行操作:操作C依赖于操作B,操作B依赖于操作A*/
225
226     //创建一个队列
227     NSOperationQueue *queue = [[NSOperationQueue alloc] init];
228
229     NSBlockOperation *operationA = [NSBlockOperation blockOperationWithBlock:^{
230         NSLog(@"A1--------%@",[NSThread currentThread]);
231     }];
232     [operationA addExecutionBlock:^{
233         NSLog(@"A2--------%@",[NSThread currentThread]);
234     }];
235     [operationA setCompletionBlock:^{
236         NSLog(@"依赖于A--------%@",[NSThread currentThread]);
237
238     }];
239     NSBlockOperation *operationB = [NSBlockOperation blockOperationWithBlock:^{
240         NSLog(@"B--------%@",[NSThread currentThread]);
241     }];
242     NSBlockOperation *operationC = [NSBlockOperation blockOperationWithBlock:^{
243         NSLog(@"C--------%@",[NSThread currentThread]);
244     }];
245     //设置依赖
246     [operationB addDependency:operationA];
247     [operationC addDependency:operationB];
248
249     [queue addOperation:operationA];
250     [queue addOperation:operationB];
251     [queue addOperation:operationC];
252 }
253
254 #pragma mark - 队列中直接添加任务
255 - (void)useNSOperationQueue
256 {
257     //1.创建operation的时候,添加一个任务
258     NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
259         NSLog(@"--------下载图片1--------%@",[NSThread currentThread]);
260     }];
261     NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
262         NSLog(@"--------下载图片2--------%@",[NSThread currentThread]);
263     }];
264
265     //2.创建队列(非主队列)会自动异步执行任务,并发
266     NSOperationQueue *queue = [[NSOperationQueue alloc] init];
267
268     //3.设置最大并发数
269     queue.maxConcurrentOperationCount = 2;
270
271     //4.添加操作到队列中
272     [queue addOperation:operation1];
273     [queue addOperation:operation2];
274
275     [queue addOperationWithBlock:^{
276         NSLog(@"--------下载图片3--------%@",[NSThread currentThread]);
277     }];
278 }
279
280 #pragma mark - 多操作添加到队列
281 - (void)useNSBlockOperation
282 {
283     //创建operation的时候,添加一个任务
284     NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
285         NSLog(@"--------下载图片1--------%@",[NSThread currentThread]);
286     }];
287     NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
288         NSLog(@"--------下载图片2--------%@",[NSThread currentThread]);
289     }];
290     //创建队列
291     NSOperationQueue *queue = [[NSOperationQueue alloc] init];
292     //主队列
293 //    NSOperationQueue *queue = [NSOperationQueue mainQueue];
294     //添加操作到队列中
295     [queue addOperation:operation1];
296     [queue addOperation:operation2];
297
298     //[operation start];
299 }
300
301 #pragma mark - NSBlockOperation
302 - (void)useBaseNSBlockOperation
303 {
304     //创建operation的时候,添加一个任务
305 //    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
306 //        NSLog(@"--------下载图片1--------%@",[NSThread currentThread]);
307 //    }];
308
309     NSBlockOperation *operation = [[NSBlockOperation alloc] init];
310     //操作中添加任务
311     [operation addExecutionBlock:^{
312         NSLog(@"--------下载图片2--------%@",[NSThread currentThread]);
313     }];
314     [operation addExecutionBlock:^{
315         NSLog(@"--------下载图片3--------%@",[NSThread currentThread]);
316     }];
317
318     //任务大于1,才会异步执行
319     [operation start];
320 }
321
322 #pragma mark - NSInvocationOperation
323 - (void)useNSInvocationOperation
324 {
325     //创建队列
326     NSOperationQueue *queue = [[NSOperationQueue alloc] init];
327     //创建操作
328     NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download) object:nil];
329
330     //opreation直接调用start,是同步执行(在当前线程执行操作)
331     //[operation start];
332
333     //添加操作到队列中,会自动异步执行
334     [queue addOperation:operation];
335 }
336
337 - (void)download
338 {
339     NSLog(@"download-------%@",[NSThread currentThread]);
340 }
341
342 - (void)didReceiveMemoryWarning {
343     [super didReceiveMemoryWarning];
344     // Dispose of any resources that can be recreated.
345 }
346
347 @end

二、防止重复下载,与沙盒缓存

 1 //
 2 //  BWApp.h
 3 //  IOS_0120_NSOperation防止重复下载
 4 //
 5 //  Created by ma c on 16/1/20.
 6 //  Copyright © 2016年 博文科技. All rights reserved.
 7 //
 8
 9 #import <Foundation/Foundation.h>
10
11 @interface BWApp : NSObject
12
13 @property (nonatomic, copy) NSString *name;
14 @property (nonatomic, copy) NSString *download;
15 @property (nonatomic, copy) NSString *icon;
16
17 + (instancetype)appWithDict:(NSDictionary *)dict;
18
19 @end
20
21 //
22 //  BWApp.m
23 //  IOS_0120_NSOperation防止重复下载
24 //
25 //  Created by ma c on 16/1/20.
26 //  Copyright © 2016年 博文科技. All rights reserved.
27 //
28
29 #import "BWApp.h"
30
31 @implementation BWApp
32
33 + (instancetype)appWithDict:(NSDictionary *)dict
34 {
35     BWApp *app = [[self alloc] init];
36     [app setValuesForKeysWithDictionary:dict];
37     return app;
38 }
39
40 @end

  1 //
  2 //  BWTableViewController.m
  3 //  IOS_0120_NSOperation防止重复下载
  4 //
  5 //  Created by ma c on 16/1/20.
  6 //  Copyright © 2016年 博文科技. All rights reserved.
  7 //
  8
  9 #import "BWTableViewController.h"
 10 #import "BWApp.h"
 11
 12 #define appImageCachesPath(url) [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:[url lastPathComponent]]
 13
 14 @interface BWTableViewController ()
 15
 16 //所有应用数据
 17 @property (nonatomic, strong) NSMutableArray *appsArray;
 18 //存放所有下载操作的队列
 19 @property (nonatomic, strong) NSOperationQueue *queue;
 20 //存放所有下载操作(url是key,operation对象是value)
 21 @property (nonatomic, strong) NSMutableDictionary *operationDict;
 22 //缓存图片
 23 @property (nonatomic, strong) NSMutableDictionary *imageDict;
 24
 25 @end
 26
 27 @implementation BWTableViewController
 28
 29 #pragma mark - 懒加载
 30 - (NSMutableArray *)appsArray
 31 {
 32     if (!_appsArray) {
 33         NSMutableArray *appArr = [[NSMutableArray alloc] init];
 34
 35         NSString *path = [[NSBundle mainBundle] pathForResource:@"apps" ofType:@"plist"];
 36
 37         NSArray *dictArr = [NSArray arrayWithContentsOfFile:path];
 38
 39         for (NSDictionary *dict in dictArr) {
 40
 41             BWApp *app = [BWApp appWithDict:dict];
 42             [appArr addObject:app];
 43         }
 44         _appsArray = appArr;
 45     }
 46     return _appsArray;
 47 }
 48
 49 - (NSOperationQueue *)queue
 50 {
 51     if (!_queue) {
 52         _queue = [[NSOperationQueue alloc] init];
 53     }
 54     return _queue;
 55 }
 56
 57 - (NSMutableDictionary *)operationDict
 58 {
 59     if (!_operationDict) {
 60         _operationDict = [[NSMutableDictionary alloc] init];
 61     }
 62     return _operationDict;
 63 }
 64
 65 - (NSMutableDictionary *)imageDict
 66 {
 67     if (!_imageDict) {
 68         _imageDict = [[NSMutableDictionary alloc] init];
 69     }
 70     return _imageDict;
 71 }
 72
 73 #pragma mark - 初始化
 74 - (void)viewDidLoad {
 75     [super viewDidLoad];
 76
 77 }
 78
 79 - (void)didReceiveMemoryWarning
 80 {
 81     [super didReceiveMemoryWarning];
 82
 83     //移除所有下载操作
 84     [self.queue cancelAllOperations];
 85     [self.operationDict removeAllObjects];
 86     //移除所有图片缓存
 87     [self.imageDict removeAllObjects];
 88 }
 89
 90
 91 #pragma mark - Table view data source
 92
 93 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
 94
 95     return 1;
 96 }
 97
 98 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
 99
100     return self.appsArray.count;
101 }
102
103 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
104     static NSString *cellID = @"cellID";
105
106     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
107
108     if (!cell) {
109         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellID];
110     }
111     //取出模型
112     BWApp *app = [self.appsArray objectAtIndex:indexPath.row];
113
114     cell.textLabel.text = app.name;
115     cell.detailTextLabel.text = app.download;
116
117     //先从imageDict缓存中取出图片url对应的image
118     UIImage *image = self.imageDict[app.icon];
119
120     if (image) { //说明图片已经下载成功过
121         cell.imageView.image = image;
122     }
123     else //说明图片未下载(没有缓存)
124     {
125         //获取caches路径,拼接文件路径
126         NSString *filePath = appImageCachesPath(app.icon);
127
128         NSData *data = [NSData dataWithContentsOfFile:filePath];
129
130         if (data) { //沙盒中存在这个图片
131             cell.imageView.image = [UIImage imageWithData:data];
132         }
133         else{
134             //显示占位图片
135             cell.imageView.image = [UIImage imageNamed:@"placeholder"];
136         }
137
138         [self download:app.icon andIndexPath:indexPath];
139     }
140     return cell;
141 }
142
143 - (void)download:(NSString *)imageUrl andIndexPath:(NSIndexPath *)indexPath
144 {
145     //取出当前图片对应的下载操作(operation对象)
146     NSBlockOperation *operation = self.operationDict[imageUrl];
147
148     if (operation)  return;
149
150 //    __weak BWTableViewController *vc = self;
151     __weak typeof(self) appVC = self;
152
153     //创建操作,下载图片
154     operation = [NSBlockOperation blockOperationWithBlock:^{
155         NSURL *url = [NSURL URLWithString:imageUrl];
156         NSData *data = [NSData dataWithContentsOfURL:url];
157         UIImage *image = [UIImage imageWithData:data];
158
159         //回到主线程
160         [[NSOperationQueue mainQueue] addOperationWithBlock:^{
161
162             //判断图片是否存在
163             if (image) {
164                 //存放图片到字典中
165                 appVC.imageDict[imageUrl] = image;
166 #warning 沙盒缓存
167                 //将图片存入沙盒之中 UIImage --> NSData --> File(文件)
168                 NSData *data = UIImagePNGRepresentation(image);
169
170 //                //获取caches路径
171 //                NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
172 //
173 //                //拼接文件路径
174 //                NSString *fileName = [imageUrl lastPathComponent];
175 //                NSString *filePath = [cachesPath stringByAppendingPathComponent:fileName];
176
177                 //写入缓存
178                 [data writeToFile:appImageCachesPath(imageUrl) atomically:YES];
179
180                 //UIImageJPEGRepresentation(UIImage * _Nonnull image, CGFloat compressionQuality)
181             }
182             //从字典中移除下载操作
183             [appVC.operationDict removeObjectForKey:imageUrl];
184             //刷新表格
185             //[self.tableView reloadData];
186             [appVC.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
187         }];
188     }];
189     //添加操作到队列中
190     [appVC.queue addOperation:operation];
191     //添加操作到字典中(为了解决重复下载)
192     appVC.operationDict[imageUrl] = operation;
193 }
194 //保证图片只下载过一次
195 //当用户开始拖拽表格时
196 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
197 {
198     //暂停下载
199     [self.queue setSuspended:YES];
200 }
201 //用户停止拖拽表格时
202 - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
203 {
204     //恢复下载
205     [self.queue setSuspended:NO];
206 }
207
208
209 @end

三、自定义NSOperation

 1 //
 2 //  BWApp.h
 3 //  IOS_0120_NSOperation防止重复下载
 4 //
 5 //  Created by ma c on 16/1/20.
 6 //  Copyright © 2016年 博文科技. All rights reserved.
 7 //
 8
 9 #import <Foundation/Foundation.h>
10
11 @interface BWApp : NSObject
12
13 @property (nonatomic, copy) NSString *name;
14 @property (nonatomic, copy) NSString *download;
15 @property (nonatomic, copy) NSString *icon;
16
17 + (instancetype)appWithDict:(NSDictionary *)dict;
18
19 @end
20
21
22 //
23 //  BWApp.m
24 //  IOS_0120_NSOperation防止重复下载
25 //
26 //  Created by ma c on 16/1/20.
27 //  Copyright © 2016年 博文科技. All rights reserved.
28 //
29
30 #import "BWApp.h"
31
32 @implementation BWApp
33
34 + (instancetype)appWithDict:(NSDictionary *)dict
35 {
36     BWApp *app = [[self alloc] init];
37     [app setValuesForKeysWithDictionary:dict];
38     return app;
39 }
40
41 @end

 1 //
 2 //  BWDownloadOperation.h
 3 //  IOS_0120_NSOperation防止重复下载
 4 //
 5 //  Created by ma c on 16/1/21.
 6 //  Copyright © 2016年 博文科技. All rights reserved.
 7 //
 8
 9 #import <Foundation/Foundation.h>
10 #import <UIKit/UIKit.h>
11
12 @class BWDownloadOperation;
13
14 @protocol BWDownloadOperationDelegate <NSObject>
15
16 @optional
17 - (void)downloadOperation:(BWDownloadOperation *)operation didFinishDownload:(UIImage *)image;
18
19 @end
20
21 @interface BWDownloadOperation : NSOperation
22
23 @property (nonatomic, copy) NSString *imageUrl;
24 @property (nonatomic, strong) NSIndexPath *indexPath;
25
26 @property (nonatomic, weak) id<BWDownloadOperationDelegate> delegate;
27
28
29 @end
30
31
32 //
33 //  BWDownloadOperation.m
34 //  IOS_0120_NSOperation防止重复下载
35 //
36 //  Created by ma c on 16/1/21.
37 //  Copyright © 2016年 博文科技. All rights reserved.
38 //
39
40 #import "BWDownloadOperation.h"
41
42 @implementation BWDownloadOperation
43
44 - (void)main
45 {
46     @autoreleasepool {
47
48         if (self.isCancelled)  return;
49
50         //创建操作,下载图片
51         NSURL *url = [NSURL URLWithString:self.imageUrl];
52         NSData *data = [NSData dataWithContentsOfURL:url];
53         UIImage *image = [UIImage imageWithData:data];
54
55         if (self.isCancelled)  return;
56
57         //回到主线程
58         [[NSOperationQueue mainQueue] addOperationWithBlock:^{
59             if ([self.delegate respondsToSelector:@selector(downloadOperation:didFinishDownload:)]) {
60                 [self.delegate downloadOperation:self didFinishDownload:image];
61             }
62         }];
63     }
64 }
65 @end

  1 //
  2 //  BWTableViewController.m
  3 //  IOS_0120_NSOperation防止重复下载
  4 //
  5 //  Created by ma c on 16/1/20.
  6 //  Copyright © 2016年 博文科技. All rights reserved.
  7 //
  8
  9 #import "BWTableViewController.h"
 10 #import "BWApp.h"
 11 #import "BWDownloadOperation.h"
 12
 13 #define appImageCachesPath(url) [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:[url lastPathComponent]]
 14
 15 @interface BWTableViewController ()<BWDownloadOperationDelegate>
 16
 17 //所有应用数据
 18 @property (nonatomic, strong) NSMutableArray *appsArray;
 19 //存放所有下载操作的队列
 20 @property (nonatomic, strong) NSOperationQueue *queue;
 21 //存放所有下载操作(url是key,operation对象是value)
 22 @property (nonatomic, strong) NSMutableDictionary *operationDict;
 23 //缓存图片
 24 @property (nonatomic, strong) NSMutableDictionary *imageDict;
 25
 26 @end
 27
 28 @implementation BWTableViewController
 29
 30 #pragma mark - 懒加载
 31 - (NSMutableArray *)appsArray
 32 {
 33     if (!_appsArray) {
 34         NSMutableArray *appArr = [[NSMutableArray alloc] init];
 35
 36         NSString *path = [[NSBundle mainBundle] pathForResource:@"apps" ofType:@"plist"];
 37
 38         NSArray *dictArr = [NSArray arrayWithContentsOfFile:path];
 39
 40         for (NSDictionary *dict in dictArr) {
 41
 42             BWApp *app = [BWApp appWithDict:dict];
 43             [appArr addObject:app];
 44         }
 45         _appsArray = appArr;
 46     }
 47     return _appsArray;
 48 }
 49
 50 - (NSOperationQueue *)queue
 51 {
 52     if (!_queue) {
 53         _queue = [[NSOperationQueue alloc] init];
 54     }
 55     return _queue;
 56 }
 57
 58 - (NSMutableDictionary *)operationDict
 59 {
 60     if (!_operationDict) {
 61         _operationDict = [[NSMutableDictionary alloc] init];
 62     }
 63     return _operationDict;
 64 }
 65
 66 - (NSMutableDictionary *)imageDict
 67 {
 68     if (!_imageDict) {
 69         _imageDict = [[NSMutableDictionary alloc] init];
 70     }
 71     return _imageDict;
 72 }
 73
 74 #pragma mark - 初始化
 75 - (void)viewDidLoad {
 76     [super viewDidLoad];
 77
 78 }
 79
 80 - (void)didReceiveMemoryWarning
 81 {
 82     [super didReceiveMemoryWarning];
 83
 84     //移除所有下载操作
 85     [self.queue cancelAllOperations];
 86     [self.operationDict removeAllObjects];
 87     //移除所有图片缓存
 88     [self.imageDict removeAllObjects];
 89 }
 90
 91
 92 #pragma mark - Table view data source
 93
 94 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
 95
 96     return 1;
 97 }
 98
 99 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
100
101     return self.appsArray.count;
102 }
103
104 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
105     static NSString *cellID = @"cellID";
106
107     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
108
109     if (!cell) {
110         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellID];
111     }
112     //取出模型
113     BWApp *app = [self.appsArray objectAtIndex:indexPath.row];
114
115     cell.textLabel.text = app.name;
116     cell.detailTextLabel.text = app.download;
117
118     //先从imageDict缓存中取出图片url对应的image
119     UIImage *image = self.imageDict[app.icon];
120
121     if (image) { //说明图片已经下载成功过
122         cell.imageView.image = image;
123     }
124     else //说明图片未下载(没有缓存)
125     {
126         //获取caches路径,拼接文件路径
127         NSString *filePath = appImageCachesPath(app.icon);
128
129         NSData *data = [NSData dataWithContentsOfFile:filePath];
130
131         if (data) { //沙盒中存在这个图片
132             cell.imageView.image = [UIImage imageWithData:data];
133         }
134         else{
135             //显示占位图片
136             cell.imageView.image = [UIImage imageNamed:@"placeholder"];
137         }
138
139         [self download:app.icon andIndexPath:indexPath];
140     }
141     return cell;
142 }
143
144 - (void)download:(NSString *)imageUrl andIndexPath:(NSIndexPath *)indexPath
145 {
146     //取出当前图片对应的下载操作(operation对象)
147     BWDownloadOperation *operation = self.operationDict[imageUrl];
148
149     if (operation)  return;
150
151     //创建操作下载图片
152     operation = [[BWDownloadOperation alloc] init];
153     operation.imageUrl = imageUrl;
154     operation.indexPath = indexPath;
155
156     //设置代理
157     operation.delegate = self;
158
159     //添加操作到队列中
160     [self.queue addOperation:operation];
161
162     //添加操作到字典中(为了解决重复下载)
163     self.operationDict[imageUrl] = operation;
164
165 }
166
167 #pragma mark - 下载代理方法
168
169 - (void)downloadOperation:(BWDownloadOperation *)operation didFinishDownload:(UIImage *)image
170 {
171
172
173     //UIImageJPEGRepresentation(<#UIImage * _Nonnull image#>, <#CGFloat compressionQuality#>)
174
175     //判断图片是否存在
176     if (image) {
177         //存放图片到字典中
178         self.imageDict[operation.imageUrl] = image;
179
180 #warning 沙盒缓存
181         //将图片存入沙盒之中 UIImage --> NSData --> File(文件)
182         NSData *data = UIImagePNGRepresentation(image);
183
184         //写入缓存
185         [data writeToFile:appImageCachesPath(operation.imageUrl) atomically:YES];
186
187     }
188     //从字典中移除下载操作(防止operationDict的下载操作越来越大,保证下载失败后能重新下载)
189     [self.operationDict removeObjectForKey:operation.imageUrl];
190     //刷新表格
191     //[self.tableView reloadData];
192     [self.tableView reloadRowsAtIndexPaths:@[operation.indexPath] withRowAnimation:UITableViewRowAnimationNone];
193 }
194
195
196 //保证图片只下载过一次
197 //当用户开始拖拽表格时
198 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
199 {
200     //暂停下载
201     [self.queue setSuspended:YES];
202 }
203 //用户停止拖拽表格时
204 - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
205 {
206     //恢复下载
207     [self.queue setSuspended:NO];
208 }
209
210
211 @end

四、SDWebImage

 1 //
 2 //  BWApp.h
 3 //  IOS_0120_NSOperation防止重复下载
 4 //
 5 //  Created by ma c on 16/1/20.
 6 //  Copyright © 2016年 博文科技. All rights reserved.
 7 //
 8
 9 #import <Foundation/Foundation.h>
10
11 @interface BWApp : NSObject
12
13 @property (nonatomic, copy) NSString *name;
14 @property (nonatomic, copy) NSString *download;
15 @property (nonatomic, copy) NSString *icon;
16
17 + (instancetype)appWithDict:(NSDictionary *)dict;
18
19 @end
20
21
22 //
23 //  BWApp.m
24 //  IOS_0120_NSOperation防止重复下载
25 //
26 //  Created by ma c on 16/1/20.
27 //  Copyright © 2016年 博文科技. All rights reserved.
28 //
29
30 #import "BWApp.h"
31
32 @implementation BWApp
33
34 + (instancetype)appWithDict:(NSDictionary *)dict
35 {
36     BWApp *app = [[self alloc] init];
37     [app setValuesForKeysWithDictionary:dict];
38     return app;
39 }
40
41 @end

  1 //
  2 //  BWTableViewController.m
  3 //  IOS_0120_NSOperation防止重复下载
  4 //
  5 //  Created by ma c on 16/1/20.
  6 //  Copyright © 2016年 博文科技. All rights reserved.
  7 //
  8
  9 #import "BWTableViewController.h"
 10 #import "BWApp.h"
 11 #import "UIImageView+WebCache.h"
 12
 13 @interface BWTableViewController ()
 14
 15 //所有应用数据
 16 @property (nonatomic, strong) NSMutableArray *appsArray;
 17
 18 @end
 19
 20 @implementation BWTableViewController
 21
 22 #pragma mark - 懒加载
 23 - (NSMutableArray *)appsArray
 24 {
 25     if (!_appsArray) {
 26         NSMutableArray *appArr = [[NSMutableArray alloc] init];
 27
 28         NSString *path = [[NSBundle mainBundle] pathForResource:@"apps" ofType:@"plist"];
 29
 30         NSArray *dictArr = [NSArray arrayWithContentsOfFile:path];
 31
 32         for (NSDictionary *dict in dictArr) {
 33
 34             BWApp *app = [BWApp appWithDict:dict];
 35             [appArr addObject:app];
 36         }
 37         _appsArray = appArr;
 38     }
 39     return _appsArray;
 40 }
 41
 42 #pragma mark - 初始化
 43 - (void)viewDidLoad {
 44     [super viewDidLoad];
 45
 46 }
 47
 48 - (void)didReceiveMemoryWarning
 49 {
 50     [super didReceiveMemoryWarning];
 51 }
 52
 53 #pragma mark - Table view data source
 54
 55 //- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
 56 //
 57 //    return 1;
 58 //}
 59
 60 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
 61
 62 //    return self.appsArray.count;
 63     return 1;
 64 }
 65
 66 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
 67
 68     static NSString *cellID = @"cellID";
 69
 70     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
 71
 72     if (!cell) {
 73         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellID];
 74     }
 75     //取出模型
 76     BWApp *app = [self.appsArray objectAtIndex:indexPath.row];
 77     //设置基本信息
 78     cell.textLabel.text = app.name;
 79     cell.detailTextLabel.text = app.download;
 80
 81     //下载图片
 82 //    NSURL *url = [NSURL URLWithString:@"http://img.cnblogs.com/ad/not-to-stop-questioning.jpg"];
 83
 84     NSURL *url = [NSURL URLWithString:app.icon];
 85     UIImage *image = [UIImage imageNamed:@"placeholder"];
 86 //    [cell.imageView sd_setImageWithURL:url placeholderImage:image];
 87
 88     SDWebImageOptions options = SDWebImageRetryFailed | SDWebImageLowPriority;
 89
 90     [cell.imageView sd_setImageWithURL:url placeholderImage:image options:options progress:^(NSInteger receivedSize, NSInteger expectedSize) {
 91
 92         NSLog(@"下载进度:%f",(double)receivedSize / expectedSize);
 93
 94     } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
 95         NSLog(@"-----图片加载完毕-----%@",image);
 96     }];
 97
 98     return cell;
 99 }
100
101 @end

1 - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
2 {
3     SDWebImageManager *maneger = [SDWebImageManager sharedManager];
4     //1.取消正在下载的操作
5     [maneger cancelAll];
6     //2.清除内存缓存
7     [maneger.imageCache clearMemory];
8     maneger.imageCache.maxCacheAge = 100*24*60*60;
9 }

转载于:https://www.cnblogs.com/oc-bowen/p/5144991.html

IOS-多线程(NSOperation)相关推荐

  1. ios多线程 -- NSOperation 简介

    NSOperation的作⽤:配合使用NSOperation和NSOperationQueue也能实现多线程编程 NSOperation和NSOperationQueue实现多线程的具体步骤: 1)先 ...

  2. ios 多线程 -- NSOperation 常用方法

    1 最大并发数 最大并发数:同一时间最多只能执行的任务的个数. 最⼤大并发数的相关⽅方法 - (NSInteger)maxConcurrentOperationCount; - (void)setMa ...

  3. iOS多线程全套:线程生命周期,多线程的四种解决方案,线程安全问题,GCD的使用,NSOperation的使用(上)

    2017-07-08 remember17 Cocoa开发者社区 目的 本文主要是分享iOS多线程的相关内容,为了更系统的讲解,将分为以下7个方面来展开描述. 多线程的基本概念 线程的状态与生命周期 ...

  4. iOS多线程:『NSOperation、NSOperationQueue』详尽总结

    2019独角兽企业重金招聘Python工程师标准>>> iOS多线程:『NSOperation.NSOperationQueue』详尽总结 转载: 原地址https://www.ji ...

  5. iOS面试题(二十五)多线程 --NSOperation和NSOperationQueueNSThread锁机制

    7.多线程 GCD(使用最多) NSOperation/NSOperationQueue(AFNetworking源码中所有网络请求任务都封装到NSOperation,提交到operationQueu ...

  6. iOS 多线程的四种技术方案

    iOS 多线程的四种技术方案 image pthread 实现多线程操作 代码实现: void * run(void *param) {for (NSInteger i = 0; i < 100 ...

  7. iOS多线程拾贝------操作巨人编程

    iOS多线程拾贝------操作巨人编程 多线程 基本 实现方案:pthread - NSThread - GCD - NSOperation Pthread 多平台,可移植 c语言,要程序员管理生命 ...

  8. IOS 多线程的一些总结

    IOS 多线程 有三种主要方法 (1)NSThread (2)NSOperation (3)GCD 下面简单介绍这三个方法 1.NSThread 调用方法如下: 如函数需要输入参数,可从object传 ...

  9. ios多线程开发的常用三种方式

    ios多线程开发的常用三种方式 1.NSThread 2.NSOperationQueue 3.GCD NSThread: 创建方式主要有两种: [NSThread detachNewThreadSe ...

  10. 多线程 循环 锁_大多数人还不清楚的iOS多线程

    你不知道的的 iOS 多线程 程序员用有限的生命去追求无限的知识. 有言在先 首先我不是故意要做标题党的,也不是我要炒冷饭,我只是想换个姿势看多线程,本文大部分内容在分析如何造死锁,奈何功力尚浅,然而 ...

最新文章

  1. 研究人员首次实现人脑实时连接互联网,攻壳社会的前奏?
  2. Python应用实战案例-Python协程管理精讲万字长文(建议收藏)
  3. Centos7-install apache+mariadb+php
  4. php如何向数组增加数据,php向数组中增加数据的方法是什么
  5. 《剑指Offer》 变态跳台阶
  6. CAN笔记(22) 特殊协议
  7. hdu2191(多重背包)
  8. java电话本怎么做_Java写的电话号码本自动化生成器,程序片段
  9. 从Qt Console Application到Qt GUI Application
  10. 在vue中安装axios库
  11. carry函数在C语言中用法,动词carry用法小归纳
  12. Qt设置字体类型及添加字体文件
  13. 搜狐CEO张朝阳决定分拆网游业务单独上市
  14. Unity3D组件 | 绘制静态柱状图
  15. 大饼“U”形底?ETR开始
  16. JAVA生成甘特图Excel导出
  17. 单位根检验urdf_R语言时间序列函数整理[转]]
  18. 推荐:(链接)幽默男女--绝对搞笑!!(每日更新)
  19. 明星热图|小S代言新品牌;黄景瑜、高圆圆、木村光希及贾樟柯拍摄品牌广告;欧阳娜娜等出席品牌活动...
  20. EDG夺冠引全网欢呼,电竞时代要来了吗?

热门文章

  1. error C2660: 'MessageBoxA' : function does not take 4 parameters
  2. xray 被动_长亭xray:一款自动化Web漏洞扫描神器(免费社区版)
  3. 服务器如何运行java文件_在linux服务器上运行java文件
  4. 017_layout排版
  5. 关于程序为什么要代码段,程序段
  6. 二叉排序树的实现——java
  7. Android开发常用第三方平台
  8. Java基础:网络编程
  9. 重启修复计算机怎么操作,如何以安全模式启动电脑,修复系统故障,这4个方法值得一试...
  10. 跨境电商自建站后台系统原型rp_外贸业务员和跨境电商运营哪个好,跨境电商可以去哪个网站学...