iOS开发多线程基础知识 NSOperation
- (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg;
- (void)start;
一旦执行操作,就会调用target的sel方法
+ (id)blockOperationWithBlock:(void (^)(void))block;
- (void)addExecutionBlock:(void (^)(void))block;
注意:只要NSBlockOperation封装的操作数 > 1,就会异步执行操作
-------NSOperationQueue----
- (void)addOperation:(NSOperation *)op;
- (void)addOperationWithBlock:(void (^)(void))block;
-------最大并发数----
- (NSInteger)maxConcurrentOperationCount;
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
-----队列的取消、暂停、恢复------
- (void)cancelAllOperations;
提示:也可以调用NSOperation的- (void)cancel方法取消单个操作
- (void)setSuspended:(BOOL)b; // YES代表暂停队列,NO代表恢复队列
- (BOOL)isSuspended;
----操作优先级-----
- (NSOperationQueuePriority)queuePriority;
- (void)setQueuePriority:(NSOperationQueuePriority)p;
[operationB addDependency:operationA]; // 操作B依赖于操作A
19.可以在不同queue的NSOperation之间创建依赖关系
20.注意:不能相互依赖
// DYFViewController.m // 624-03-NSOperation // // Created by dyf on 14-6-24. // Copyright (c) 2014年 ___FULLUSERNAME___. All rights reserved. // #import "DYFViewController.h" @interface DYFViewController () @end @implementation DYFViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. [self testOperationQueue]; } - (void)testOperationListen { NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"下载图片1111111%@", [NSThread currentThread]); // 下载图片 }]; operation3.completionBlock = ^{ // 下载完图片后想做的时期 }; // 2.创建队列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; [queue addOperation:operation3]; } - (void)testOperationQueue { // 1.封装操作 NSInvocationOperation *operation1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download) object:nil]; NSInvocationOperation *operation2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil]; NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"1111111%@", [NSThread currentThread]); }]; [operation3 addExecutionBlock:^{ NSLog(@"222222%@", [NSThread currentThread]); }]; [operation3 addExecutionBlock:^{ NSLog(@"33333%@", [NSThread currentThread]); }]; // 2.创建队列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; // 5以内,2~3为宜 queue.maxConcurrentOperationCount = 2; #warning 面试题 // 设置操作依赖(一定要在添加到队列中前设置) [operation2 addDependency:operation1]; // 执行顺序取决于依赖,先执行完operation1再执行operation2 // 注意:不能相互依赖,循环操作 // 3.添加操作到队列中(自动执行操作,自动开启线程) [queue addOperation:operation1]; [queue addOperation:operation2]; [queue addOperation:operation3]; // 取消所有线程 //[queue cancelAllOperations]; // 暂停队列 //[queue setSuspended:YES]; // 设置操作优先级 //operation1.queuePriority = NSOperationQueuePriorityVeryHigh; } - (void)testNSBlockOperation { // 1.创建操作对象,封装要执行的任务 NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ for (int i = 0; i < 11; i++) { NSLog(@"1111111%@", [NSThread currentThread]); } }]; // 任务数在2各以上,就会开线程 [operation addExecutionBlock:^{ for (int i = 0; i < 11; i++) { NSLog(@"222222%@", [NSThread currentThread]); } }]; [operation addExecutionBlock:^{ for (int i = 0; i < 11; i++) { NSLog(@"33333%@", [NSThread currentThread]); } }]; // 2.执行操作 [operation start]; } - (void)testNSInvocationOperation { // 1.创建操作对象,封装要执行的任务 NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download) object:nil]; // 2.执行操作(默认情况下,若操作没有放到队列queue中,都是同步执行) [operation start]; } - (void)download { for (int i = 0; i < 11; i++) { NSLog(@"download-----%@", [NSThread currentThread]); } } - (void)run { for (int i = 0; i < 11; i++) { NSLog(@"run------%@", [NSThread currentThread]); } } @end
----自定义NSOperation---
// // DYFDownloadOperation.h // 624-05-自定义Operation // // Created by dyf on 14-6-24. // Copyright (c) 2014年 dyf. All rights reserved. // #import <Foundation/Foundation.h> @class DYFDownloadOperation; @protocol DYFDownloadOperationDelegate <NSObject> @optional - (void)downloadOperation:(DYFDownloadOperation *)operation didFinishedDownload:(UIImage *)image; @end @interface DYFDownloadOperation : NSOperation @property (nonatomic, copy) NSString *url; @property (nonatomic, strong) NSIndexPath *indexPath; @property (nonatomic, weak) id<DYFDownloadOperationDelegate> delegate; @end
// // DYFDownloadOperation.m // 624-05-自定义Operation // // Created by dyf on 14-6-24. // Copyright (c) 2014年 dyf. All rights reserved. // #import "DYFDownloadOperation.h" @implementation DYFDownloadOperation /** * 在main方法中实现具体操作 */ - (void)main { @autoreleasepool { if (self.isCancelled) return; NSURL *imaUrl = [NSURL URLWithString:self.url]; if (self.isCancelled) return; // 下面这行很耗时 NSData *data = [NSData dataWithContentsOfURL:imaUrl]; if (self.isCancelled) return; UIImage *image = [UIImage imageWithData:data]; if (self.isCancelled) return; // 返回主线程显示图片 // 通过代理 if ([self.delegate respondsToSelector:@selector(downloadOperation:didFinishedDownload:)]) { [self.delegate downloadOperation:self didFinishedDownload:image]; } } } @end
具体利用MVC模式创建的文件老生常谈,只来一个Controller.m文件供参考,数据存储存在问题,可以改用SDWebImage框架处理
// // DYFTableViewController.m // 624-05-自定义Operation // // Created by dyf on 14-6-24. // Copyright (c) 2014年 ___FULLUSERNAME___. All rights reserved. // #import "DYFTableViewController.h" #import "DYFAppModel.h" #import "DYFDownloadOperation.h" #warning Dictionary基础知识不太理解,字典的赋值回去看看笔记 @interface DYFTableViewController ()<DYFDownloadOperationDelegate> @property (nonatomic, strong) NSArray *apps; @property (nonatomic, strong) NSOperationQueue *queue; /** * key:url value:operation对象 */ @property (nonatomic, strong) NSMutableDictionary *oprations; /** * key:url value:image对象 */ @property (nonatomic, strong) NSMutableDictionary *images; @end @implementation DYFTableViewController #pragma mark - 4个懒加载 - (NSArray *)apps { if (!_apps) { NSString *path = [[NSBundle mainBundle] pathForResource:@"apps" ofType:@"plist"]; NSArray *arrayApps = [NSArray arrayWithContentsOfFile:path]; NSMutableArray *arrayM = [NSMutableArray arrayWithCapacity:arrayApps.count]; for (NSDictionary *dict in arrayApps) { DYFAppModel *appM = [DYFAppModel appWithDict:dict]; [arrayM addObject:appM]; } _apps = arrayM; } return _apps; } - (NSOperationQueue *)queue { if (!_queue) { _queue = [[NSOperationQueue alloc] init]; // 设置最大并发线程数,最多同时下载3张图片 _queue.maxConcurrentOperationCount = 3; } return _queue; } - (NSMutableDictionary *)oprations { if (!_oprations) { _oprations = [[NSMutableDictionary alloc] init]; } return _oprations; } - (NSMutableDictionary *)images { if (!_images) { _images = [NSMutableDictionary dictionary]; } return _images; } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. } #pragma mark - 数据源方法 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.apps.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // 1.创建cell static NSString *identifier = @"apps"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier]; if (!cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier]; } // 2.设置cell的数据 DYFAppModel *app = self.apps[indexPath.row]; cell.textLabel.text = app.name; cell.detailTextLabel.text = app.download; // 重点是如何从网络下载图片传入cell上面 // 每个url对应一个DYFDownloadOperation对象 // 每个url对应一个image对象 UIImage *image = self.images[app.icon]; if (image) { // 若缓存中存在图片 cell.imageView.image = image; }else { // 若缓存中不存在图片,则图片要从网上下载 // 设置下载前系统刷出的图片 cell.imageView.image = [UIImage imageNamed:@"身份证小"]; // 基础差,下面这行不太理解 DYFDownloadOperation *operation = self.oprations[app.icon]; if (operation) { // 若正在下载,则不执行其它操作 }else { // 若没在下载,则创建开始下载的子线程 DYFDownloadOperation *operation = [[DYFDownloadOperation alloc] init]; operation.url = app.icon; operation.indexPath = indexPath; operation.delegate = self; // 添加任务进队列,异步下载 [self.queue addOperation:operation]; // 基础差,下面这行不太理解 self.oprations[app.icon] = operation; } } // 3.返回cell return cell; } #pragma mark - DYFDownloadOperationDelegate - (void)downloadOperation:(DYFDownloadOperation *)operation didFinishedDownload:(UIImage *)image { // 1.删除执行完毕的下载操作 [self.oprations removeObjectForKey:operation.url]; // 若图片下载好 if (image) { // 2.将下载好的图片存入缓存 self.images[operation.url] = image; // 3.刷新这一行cell的数据 [self.tableView reloadRowsAtIndexPaths:@[operation.indexPath] withRowAnimation:UITableViewRowAnimationNone]; // 4.将图片存入沙盒 // 4.1图片先转换为2进制数据 NSData *data = UIImagePNGRepresentation(image); // 4.2设置沙盒路径 NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:[self.apps[operation.indexPath.row] icon]]; NSLog(@"%@", path); // 4.3保存data到path中 [data writeToFile:path atomically:YES]; } } // 开始拖拽时候暂停队列 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { [self.queue setSuspended:YES]; } // 停止拖拽的时候重启队列 - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { [self.queue setSuspended:NO]; } @end