NSOperation具体使用:直接继承NSObject
它的子类有:NSBlockOperation、NSInvocationOperation
还有一个必须的类,队列,用来装创建的线程 NSOperationQueue
理解:这个方式是如何实现多线程呢?是通过操作队列来实现多线程的。即主线程是一个主队列,再创建一个队列并将其他的线程加入其中同步执行。如果对共享资源的争夺放在主线程队列中,则不需要关心线程管理,数据同步的事情,可以把精力放在自己需要执行的操作上;否则的话,仍需要关心数据同步的问题。
说明:
一般用子类创建Operation实例来实现多线程,NSBlockOperation、NSInvocationOperation这两种方式均可以使用,前一个采用的是将线程的执行过程封装为block函数,第二个采用的是将线程的执行过程封装为方法。
1、NSOperation的详解:
队列优先级枚举:
typedef NS_ENUM(NSInteger, NSOperationQueuePriority) {
NSOperationQueuePriorityVeryLow = -8L,
NSOperationQueuePriorityLow = -4L,
NSOperationQueuePriorityNormal = 0,
NSOperationQueuePriorityHigh = 4,
NSOperationQueuePriorityVeryHigh = 8
};
属性:
@property (readonly, getter=isCancelled) BOOL cancelled; //线程是否取消
@property (readonly, getter=isExecuting) BOOL executing; //线程是否在执行
@property (readonly, getter=isFinished) BOOL finished; //线程是否执行完毕
@property (readonly, getter=isConcurrent) BOOL concurrent; //线程是否并发执行
@property (readonly, getter=isAsynchronous) BOOL asynchronous; //是否线程异步,已经被线程同步覆盖
@property (readonly, getter=isReady) BOOL ready; //线程是否处于就绪状态
@property (readonly, copy) NSArray *dependencies; //线程依赖的数组
@property NSOperationQueuePriority queuePriority; //队列优先级
@property (copy) void (^completionBlock)(void); //block函数
@property double threadPriority; //线程优先级
@property NSQualityOfService qualityOfService; //服务质量
@property (copy) NSString *name; //线程名字
方法:
- (void)start; //启动线程
- (void)main; //主线程
- (void)cancel;//取消线程
- (void)addDependency:(NSOperation *)op; //添加线程依赖(只有上一个线程一直执行,依赖的下一个线程才开始执行)
- (void)removeDependency:(NSOperation *)op; //移除线程依赖
- (void)waitUntilFinished //等待抢占资源的线程结束
================================================================================
2、NSIndivocationOperation的详解:NSInvocationOperation : NSOperation
属性:
@property (readonly, retain) NSInvocation *invocation; //线程的调用
@property (readonly, retain) id result;
方法:
//创建线程的实例方法,可以添加线程事件
- (instancetype)initWithTarget:(id)target selector:(SEL)sel object:(id)arg;
//创建线程的实例方法
- (instancetype)initWithInvocation:(NSInvocation *)inv ;
=================================================================
3、NSBlockOperation的详解:NSBlockOperation : NSOperation
属性:@property (readonly, copy) NSArray *executionBlocks; //执行block的线程队列数组
方法:
※创建线程的类方法,执行block函数
+ (instancetype)blockOperationWithBlock:(void (^)(void))block;
※添加执行线程对列block函数
- (void)addExecutionBlock:(void (^)(void))block;
==========================================================
4、NSOperationQueue队列的详解:NSOperationQueue : NSOperation
属性:
@property (readonly, copy) NSArray *operations; //操作线程数组
@property (readonly) NSUInteger operationCount //一次能执行的线程数量
@property NSInteger maxConcurrentOperationCount; // 能并发执行的最大线程数量
@property (getter=isSuspended) BOOL suspended; //是否暂时线程
@property (copy) NSString *name ; //线程名字
@property NSQualityOfService qualityOfService; //服务质量
@property (assign /* actually retain */) dispatch_queue_t underlyingQueue;
方法:
※添加线程
- (void)addOperation:(NSOperation *)op;
※等待添加线程数组
- (void)addOperations:(NSArray *)ops waitUntilFinished:(BOOL)wait;
※添加线程并执行block函数的实例方法
- (void)addOperationWithBlock:(void (^)(void))block;
※取消所有的线程
- (void)cancelAllOperations;
※等待所有的线程执行完毕
- (void)waitUntilAllOperationsAreFinished;
※当前队列
+ (NSOperationQueue *)currentQueue;
※主队列
+ (NSOperationQueue *)mainQueue;
具体举例如下:多线程卖票(将当前票数和线程名字显示在文本视图中)
方法一:采用NSOpeartion的子类NSIndivocationOperation创建多线程:
1.文本视图控件并关联以及声明票属性
@interface ViewController () { int tickets; } @property (weak, nonatomic) IBOutlet UITextView *textView;
2.设置票数和文本视图
//准备数据 tickets = 20; //设置textView self.textView.text = @""; self.textView.layoutManager.allowsNonContiguousLayout = NO;
3.创建NSOperation实例(线程)
//创建NSOperation并加到队列 NSInvocationOperation *operation1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(operationSellMethod:) object:@"售票线程-1"]; NSInvocationOperation *operation2 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(operationSellMethod:) object:@"售票线程-2"];
4.将operation加入创建的队列中
//创建队列 NSOperationQueue *queue = [[NSOperationQueue alloc]init]; //为操作之间添加依赖,只有被依赖的线程执行完,依赖的线程才能执行 //[operation1 addDependency:operation2]; //将opearion放入队列 [queue addOperation:operation1]; [queue addOperation:operation2];
5.更新UI的主线程队列
#pragma mark -更新UI
-(void)appendTextView:(NSString *)text { //1.获取原来的内容 NSMutableString *content = [[NSMutableString alloc]initWithString:self.textView.text]; NSRange range = NSMakeRange(content.length, 1); //2.追加新的内容 [content appendString:[NSString stringWithFormat:@"\n%@",text]]; [self.textView setText:content]; //3.滚动视图 [self.textView scrollRangeToVisible:range]; }
6.执行对共享抢占资源操作的过程
#pragma mark -执行线程过程
-(void)operationSellMethod:(NSString*)name { while (YES) { //1.判断是否有票 if (tickets>0) { //没有将共享抢占资源放到主队列中,仍然要关心数据同步的问题 @synchronized(self) { NSString *info = [NSString stringWithFormat:@"总的票数:%d,当前的线程:%@",tickets,name]; [[NSOperationQueue mainQueue]addOperationWithBlock:^{ [self appendTextView:info]; }]; //2.卖票 tickets--; } //3.线程休眠 if([name isEqualToString:@"售票线程-1"]) { [NSThread sleepForTimeInterval:0.3f]; } else { [NSThread sleepForTimeInterval:0.2f]; } } else { //更新UI NSString *info = [NSString stringWithFormat:@"票已经售完,当前的线程:%@",name]; [[NSOperationQueue mainQueue] addOperationWithBlock:^{ [self appendTextView:info]; }]; //退出线程 break; } } }
方法二:采用NSOpeartion的子类NSBlockOperation创建多线程:
1.文本视图控件并关联以及声明票属性
@interface ViewController () { int tickets; } @property (weak, nonatomic) IBOutlet UITextView *textView;
2.设置票数和文本视图
//准备数据 tickets = 20; //设置textView self.textView.text = @""; self.textView.layoutManager.allowsNonContiguousLayout = NO;
3.创建队列和操作block线程
//创建队列 NSOperationQueue *queue = [[NSOperationQueue alloc]init]; //设置并行的线程数量 //[queue setMaxConcurrentOperationCount:2]; //在队列中添加block的operation [queue addOperationWithBlock:^{ [self operationSellMethod:@"售票线程-1"]; }]; [queue addOperationWithBlock:^{ [self operationSellMethod:@"售票线程-2"]; }]; NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{ [self operationSellMethod:@"售票线程-3"]; }]; [queue addOperation:blockOperation];
4.更新UI的主线程队列
#pragma mark -更新UI
-(void)appendTextView:(NSString *)text { //1.获取原来的内容 NSMutableString *content = [[NSMutableString alloc]initWithString:self.textView.text]; NSRange range = NSMakeRange(content.length, 1); //2.追加新的内容 [content appendString:[NSString stringWithFormat:@"\n%@",text]]; [self.textView setText:content]; //3.滚动视图 [self.textView scrollRangeToVisible:range]; }
5.执行对共享抢占资源操作的过程
#pragma mark -执行线程过程
#pragma mark -执行线程过程 -(void)operationSellMethod:(NSString*)name { while (YES) { //1.判断是否有票 if (tickets>0) { //将共享抢占资源放入主队列,不需要再关心数据同步的问题 [[NSOperationQueue mainQueue]addOperationWithBlock:^{ NSString *info = [NSString stringWithFormat:@"总的票数:%d,当前的线程:%@",tickets,name]; [self appendTextView:info]; //2.卖票 tickets--; }]; //3.线程休眠 if([name isEqualToString:@"售票线程-1"]) { [NSThread sleepForTimeInterval:0.3f]; } else { [NSThread sleepForTimeInterval:0.2f]; } } else { //更新UI NSString *info = [NSString stringWithFormat:@"票已经售完,当前的线程:%@",name]; [[NSOperationQueue mainQueue] addOperationWithBlock:^{ [self appendTextView:info]; }]; //退出线程 break; } } }
演示结果如下: