您的位置:首页 > 移动开发 > IOS开发

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



                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: