您的位置:首页 > 产品设计 > UI/UE

IOS多线程(NSOperation,NSOperationQueue)

2013-09-15 23:08 302 查看
含义:NSOperation,NSOperationQueue是什么。

The
NSOperation
class is an abstract class you use to encapsulate the code and data associated with a single task.NSOperation是一个你需要将代码和数据放在一个单任务中执行的抽象类。

The
NSOperationQueue
class regulates the execution of a set of
NSOperation
objects.NSOperationQueue是用来管理多个NSOperation对象的一个类。

2.使用方法

使用 NSOperation的方式有两种,

一种是用定义好的两个子类:

NSInvocationOperation 和 NSBlockOperation。

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad
{
[super viewDidLoad];
NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self
selector:@selector(downloadImage:)
object:kURL];

NSOperationQueue *queue = [[NSOperationQueue alloc]init];
[queue addOperation:operation];
// Do any additional setup after loading the view, typically from a nib.
}

-(void)downloadImage:(NSString *)url{
NSLog(@"url:%@", url);
NSURL *nsUrl = [NSURL URLWithString:url];
NSData *data = [[NSData alloc]initWithContentsOfURL:nsUrl];
UIImage * image = [[UIImage alloc]initWithData:data];
[self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];
}
-(void)updateUI:(UIImage*) image{
self.imageView.image = image;
}


2.另一种则是继承NSOperation,重写NSOperation的main方法

编写一个NSOperation的子类,只需实现main方法。这里非常类似Java的Thread,你可以继承它,并覆盖run方法,在该方法里面写入需要执行的代码。这里的main方法和run方法作用是相似的。

@interface MyTask : NSOperation {
int operationId;
}

@property int operationId;

@end


这里的operationId属性不是必须的,是我想在后面标识区分多个Task的标识位。

@implementation MyTask

@synthesize operationId;

- (void)main{
NSLog(@"task %i run … ",operationId);
[NSThread sleepForTimeInterval:10];
NSLog(@"task %i is finished. ",operationId);
}

@end


View Code
这里模拟了一个耗时10秒钟的操作。

2011-07-18 15:59:14.622 MultiThreadTest[24271:6103] task 1 run …
2011-07-18 15:59:24.623 MultiThreadTest[24271:6103] task 1 is finished.


可以向操作队列(NSOperationQueue)增加多个操作,比如这样:

下面需要把Task加入到队列中:

- (void)viewDidLoad {
[super viewDidLoad];
queue=[[NSOperationQueue alloc] init];

int index=1;
MyTask *task=[[[MyTask alloc] init] autorelease];
task.operationId=index++;

[queue addOperation:task];


我直接找了个Controller的方法写上了。运行结果是,界面出现了,而task还未执行完,说明是多线程的。10秒钟后,日志打印完毕,类似这样:

- (void)viewDidLoad {
[super viewDidLoad];
queue=[[NSOperationQueue alloc] init];

int index=1;
MyTask *task=[[[MyTask alloc] init] autorelease];
task.operationId=index++;
[queue addOperation:task];

task=[[[MyTask alloc] init] autorelease];
task.operationId=index++;

[queue addOperation:task];
}


那么打印出的内容是不定的,有可能是这样:

2011-07-18 15:49:48.087 MultiThreadTest[24139:6203] task 1 run …
2011-07-18 15:49:48.087 MultiThreadTest[24139:1903] task 2 run …
2011-07-18 15:49:58.122 MultiThreadTest[24139:6203] task 1 is finished.
2011-07-18 15:49:58.122 MultiThreadTest[24139:1903] task 2 is finished.


甚至有可能是这样:

2011-07-18 15:52:24.686 MultiThreadTest[24168:1b03] task 2 run …
2011-07-18 15:52:24.685 MultiThreadTest[24168:6003] task 1 run …
2011-07-18 15:52:34.708 MultiThreadTest[24168:1b03] task 2 is finished.
2011-07-18 15:52:34.708 MultiThreadTest[24168:6003] task 1 is finished.


因为两个操作提交的时间间隔很近,线程池中的线程,谁先启动是不定的。

那么,如果需要严格意义的顺序执行,怎么办呢?

处理操作之间的依赖关系

如果操作直接有依赖关系,比如第二个操作必须等第一个操作结束后再执行,需要这样写:

queue=[[NSOperationQueue alloc] init];

int index=1;
MyTask *task=[[[MyTask alloc] init] autorelease];
task.operationId=index++;

[queue addOperation:task];

task=[[[MyTask alloc] init] autorelease];
task.operationId=index++;

if ([[queue operations] count]>0) {
MyTask *theBeforeTask=[[queue operations] lastObject];
[task addDependency:theBeforeTask];
}

[queue addOperation:task];


这样,即使是多线程情况下,可以看到操作是严格按照先后次序执行的。

控制线程池中的线程数

可以通过类似下面的代码:

[queue setMaxConcurrentOperationCount:2];


来设置线程池中的线程数,也就是并发操作数。默认情况下是-1,也就是没有限制,同时运行队列中的全部操作。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: