IOS开发 - 多线程 NSOperation
2015-10-23 23:40
453 查看
1,NSOperation使用
1)NSOperation简介
NSOperation是Cocoa中的一个抽象类,用来封装单个任务和代码执行一项操作,由于是抽象类,所以不能直接实例化使用,必须定义子类继承该抽象类来实现,比较常用的NSOperation的子类有NSInvocationOperation,另外,也可以自己继承NSOperation来实现线程的操作。另外会使用到操作队列NSOperationQueue,它相当于一个线程队列或者可以叫做线程池,可以顺序执行队列中的操作,也可以设置队列中操作的优先级。
NSOperation有两个子类,NSInvocationOperation 和 NSBlockOperation。NSOperation也是设计用来扩展的,只需继承重写NSOperation的一个方法main。
2)NSOperation和GCD
/**GCD --> IOS4.0
-GCD --> iOS 4.0
- 将任务(block)添加到队列(串行/并发(全局)),指定 执行任务的方法(同步(阻塞)/异步)
- 拿到 dispatch_get_main_queue()。 线程间通信
- NSOperation无法做到,一次性执行,延迟执行,调度组(op相对复杂)
NSOperation ----> iOS 2.0 (后来苹果改造了NSOperation的底层)
- 将操作(异步执行)添加到队列(并发/全局)
- [NSOperationQueue mainQueue] 主队列。 任务添加到主队列, 就会在主线程执行
- 提供了一些GCD不好实现的,”最大并发数“
- 暂停/继续 --- 挂起
- 取消所有的任务
- 依赖关系
*/
/**
小结一下:
只要是NSOperation的子类 就能添加到操作队列
- 一旦操作添加到队列, 就会自动异步执行
- 如果没有添加到队列, 而是使用start方法,会在当前线程执行操作
- 如果要做线程间通信,可以使用[NSOperationQueue mainQueue]拿到主队列,往主队列添加操作(更新UI)
*/
3)NSOperation多线程Demo
基本用法
#pragma mark - 基本使用 // MARK : 线程间通信 最重要的代码 // 线程间的通信,代码实现,子线程中获取主线程,并在主线程中添加操作,可以嵌套 - (void)opDemo5 { NSOperationQueue *queue = [[NSOperationQueue alloc] init]; [queue addOperationWithBlock:^{ NSLog(@"耗时操作"); [NSThread sleepForTimeInterval:2]; //去主线程更新UI [[NSOperationQueue mainQueue] addOperationWithBlock:^{ NSLog(@"更新UI"); }]; }]; } //MARk : NSBlockOperation使用 // 如下所示,NSBlockOperation,NSInvocationOperation两种对象可以同时放到一个队列中执行的,就是说是可以混合使用的 - (void)opDemo4 { NSOperationQueue *queue = [[NSOperationQueue alloc] init]; for (int i = 0; i < 10; i++) { //直接使用队列的方法将操作添加到队列中去 [queue addOperationWithBlock:^{ [NSThread sleepForTimeInterval:1]; NSLog(@"%@", [NSThread currentThread]); }]; } //创建一个NSBlockOperation操作对象 NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ [NSThread sleepForTimeInterval:1]; NSLog(@"op1-----%@", [NSThread currentThread]); }]; //他们两个的执行顺序是不确定的 [op1 addExecutionBlock:^{ [NSThread sleepForTimeInterval:1]; NSLog(@"op1---op1"); }]; [queue addOperation:op1]; //创建并添加 NSInvocationOperation NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downloadImage:) object:@"abc"]; [queue addOperation:op2]; } //MARK : NSBlockOperation使用 - (void)opDemo3 { NSOperationQueue *queue = [[NSOperationQueue alloc] init]; //获取主队列, 和GCD中的主队列一个道理 NSOperationQueue *q = [NSOperationQueue mainQueue]; for (int i = 0; i < 10; i++) { NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ [NSThread sleepForTimeInterval:1]; NSLog(@"%@", [NSThread currentThread]); }]; [queue addOperation:op]; } NSLog(@"done"); } //MARK : 多个 NSInvocationOperation 使用 - (void)opDemo2 { //队列,在GCD中并发(全局)队列使用的最多。所以NSoperation技术直接把GCD里面的并发队列封装起来 //NSOperationQueue队列,本质就是GCD里面的并发队列 //操作就是GCD里面异步执行任务 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; //把多个操作放到队列中去 for(int i = 0; i < 10; i++) { NSOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downloadImage:) object:@"sdsdsd"]; [queue addOperation:op]; } } // MARK : 单个 NSInvocationOperation 的使用 - (void)opDemo1 { //1,创建操作 NSOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downloadImage:) object:@"downloadImage"]; //2,启动 使用这个方法时候,会直接在当前线程中执行任务,达不到多线程的目的 // [op start]; //3,只要把操作添加到队列中, 就会自动的异步执行 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; [queue addOperation:op]; NSLog(@"111%s", __func__); } - (void)downloadImage:(NSString *)picName { // NSLog(@"%s", __func__); [NSThread sleepForTimeInterval:1]; NSLog(@"%@ ----- %@", [NSThread currentThread], picName); }
高级用法
#pragma mark - 高级操作 // MARk : 依赖关系 - (void)dependecy { /* 例如: 1,登陆账号 2,下载一张图片, 3,图片更新到UI上 这三个操作是有先后顺序的, 为了处理并发中的这种先后顺序,需要使用依赖关系 */ NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"1,登陆账号 %@", [NSThread currentThread]); }]; NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"2,下载一张图片 %@", [NSThread currentThread]); }]; NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"3,更绣UI %@", [NSThread currentThread]); }]; [op2 addDependency:op1]; [op3 addDependency:op2]; //如果出现循环依赖,程序就会死锁 // [op3 addDependency:op1]; //watiUntilFinished 类似GCD调度组的通知 //NO 不等待,会直接执行 //YES 等待上面的操作执行结束,再 执行 [self.queue addOperations:@[op1, op2] waitUntilFinished:YES]; NSLog(@"test"); //在主线程中更新UI [[NSOperationQueue mainQueue] addOperation:op3]; NSLog(@"here"); } // MARK : 取消队列中所有的操作 // 取消操作并不会影响队列的挂起状态 - (IBAction)cancleAll:(id)sender{ //取消队列中所有操作 [self.queue cancelAllOperations]; NSLog(@"取消当前队列中所有的操作"); //取消队列的挂起状态 self.queue.suspended = NO; } // MARK : 暂停/继续 对队列中任务的暂停和继续 - (IBAction)pause:(id)sender { //判断操作的数量,看队列中是不是有操作 if (self.queue.operationCount == 0) { NSLog(@"没有操作"); return; } // 暂停/继续 self.queue.suspended = !self.queue.suspended; // 队列挂起以后队列中的任务还是有的 if (self.queue.suspended) { NSLog(@"暂停"); }else{ NSLog(@"继续"); } } // MARk : 最大并发数 - (void)opDemo6 { //设置最大并发数,并不是线程的数量 // 这里设置最大并发数量,设置的是最多同时有多少个线程在执行,这里有个线程池的概念,当程序需要线程的时候,就会从线程池中取出一个线程,线程使用完毕时候还会放回线程池中去,在需要的识货再去线程池中取,线程使用的过程中还有个回收的过程 self.queue.maxConcurrentOperationCount = 3; for (int i = 0; i < 20; i++) { NSOperation *op = [NSBlockOperation blockOperationWithBlock:^{ [NSThread sleepForTimeInterval:1.0]; NSLog(@"%@---%d", [NSThread currentThread], i); }]; [self.queue addOperation:op]; } }
2,NSOperation
<pre name="code" class="objc">@interface NSOperation : NSObject { @private id _private; int32_t _private1; #if __LP64__ int32_t _private1b; #endif } //1,通过这个方法可以启动一个操作,但是操作只会在当前的线程中执行,相当于是同步执行 - (void)start; - (void)main; //2,取消当前的操作 @property (readonly, getter=isCancelled) BOOL cancelled; - (void)cancel; @property (readonly, getter=isExecuting) BOOL executing; //判断当前操作是否正在执行 @property (readonly, getter=isFinished) BOOL finished; //判断当前操作是否执行完成 @property (readonly, getter=isConcurrent) BOOL concurrent; // To be deprecated; use and override 'asynchronous' below @property (readonly, getter=isAsynchronous) BOOL asynchronous NS_AVAILABLE(10_8, 7_0); @property (readonly, getter=isReady) BOOL ready; //3,添加依赖关系 和 移除依赖关系 - (void)addDependency:(NSOperation *)op; - (void)removeDependency:(NSOperation *)op; //4,获取当前操作所有的依赖关系 @property (readonly, copy) NSArray *dependencies; typedef NS_ENUM(NSInteger, NSOperationQueuePriority) { NSOperationQueuePriorityVeryLow = -8L, NSOperationQueuePriorityLow = -4L, NSOperationQueuePriorityNormal = 0, NSOperationQueuePriorityHigh = 4, NSOperationQueuePriorityVeryHigh = 8 }; //5,设置当前操作的优先级 @property NSOperationQueuePriority queuePriority; //6,设置当前操作完成之后要执行的代码 @property (copy) void (^completionBlock)(void) NS_AVAILABLE(10_6, 4_0); //7,等待完成之后继续操作 - (void)waitUntilFinished NS_AVAILABLE(10_6, 4_0); @property double threadPriority NS_DEPRECATED(10_6, 10_10, 4_0, 8_0); @property NSQualityOfService qualityOfService NS_AVAILABLE(10_10, 8_0); @property (copy) NSString *name NS_AVAILABLE(10_10, 8_0); @end
3,NSBlockOperation
@interface NSBlockOperation : NSOperation { @private id _private2; void *_reserved2; } //1,类方法创建一个操作 + (instancetype)blockOperationWithBlock:(void (^)(void))block; //2,向这个操作中添加子操作,子操作和当前操作执行顺序是不确定的,子操作和当前操作并没有什么联系。 - (void)addExecutionBlock:(void (^)(void))block; @property (readonly, copy) NSArray *executionBlocks; @end
4,NSInvocationOperation
@interface NSInvocationOperation : NSOperation { @private id _inv; id _exception; void *_reserved2; } //1,通过一个实例方法,创建一个操作,并制定操作要执行的方法,缺点是,必须指定一个要执行的方法,异步执行的代码块要放到一个新的方法中去执行。 - (instancetype)initWithTarget:(id)target selector:(SEL)sel object:(id)arg; - (instancetype)initWithInvocation:(NSInvocation *)inv NS_DESIGNATED_INITIALIZER; @property (readonly, retain) NSInvocation *invocation; @property (readonly, retain) id result; @end
5,NSOperationQueue
<pre name="code" class="objc">@interface NSOperationQueue : NSObject { @private id _private; void *_reserved; } //1,向队列中添加操作 - (void)addOperation:(NSOperation *)op; //2,使用数组的方式,向队列中添加操作,并设置是否对等待 - (void)addOperations:(NSArray *)ops waitUntilFinished:(BOOL)wait NS_AVAILABLE(10_6, 4_0); //3,通过block代码块来向队列中添加操作,一种更快捷的方式,无需创建NSOperation对象 - (void)addOperationWithBlock:(void (^)(void))block NS_AVAILABLE(10_6, 4_0); //4,取出队列中的操作,只读 @property (readonly, copy) NSArray *operations; //5,队列中的操作数(任务数) @property (readonly) NSUInteger operationCount NS_AVAILABLE(10_6, 4_0); //6,队列中最大并发数,最多能够同时执行多少个任务 @property NSInteger maxConcurrentOperationCount; enum { NSOperationQueueDefaultMaxConcurrentOperationCount = -1 }; //7,挂起,将队列中的任务挂起,暂停任务,挂起之后,队列中的任务不再 取出执行,但是任务还存在在队列中 @property (getter=isSuspended) BOOL suspended; @property (copy) NSString *name NS_AVAILABLE(10_6, 4_0); @property NSQualityOfService qualityOfService NS_AVAILABLE(10_10, 8_0); @property (assign /* actually retain */) dispatch_queue_t underlyingQueue NS_AVAILABLE(10_10, 8_0); //8,取消所有的操作 - (void)cancelAllOperations; //9,相当于是GCD调度组中的通知,在队列中所有的任务都执行完成之后会调用这个方法 - (void)waitUntilAllOperationsAreFinished; //10,获取当前所在队列,获取主队列 + (NSOperationQueue *)currentQueue NS_AVAILABLE(10_6, 4_0); + (NSOperationQueue *)mainQueue NS_AVAILABLE(10_6, 4_0); @end
相关文章推荐
- iOS学习笔记之文件的压缩和解压(zip)
- iOS-捕获应用程序崩溃日志
- iOS开发常见error
- iOS多线程1 Operation
- iOS定义常量的最佳实践
- iOS中 常用的mac终端指令汇总 技术分享
- iOS中 常用的mac终端指令汇总 技术分享
- IOS TextField设置大全
- iOS项目问题汇总<三>
- iOS体会篇 大学编程到公司的过程
- iOS体会篇 大学编程到公司的过程
- iOS切换Statusbar黑白状态
- 第一个iOS应用程序开发
- ios:开始判断星期几
- iOS消息传递机制
- 蓝懿ios 技术内容和心得 10。23
- IOS-自定义cell与控件布局
- ios学习之cocoa的大致了解
- iOS-响应上下左右滑动手势
- iOS开发中使用宏定义提高开发效率