NSOperation和NSOperationQueue

NSOperation

1.继承NSOperation类

2.重写“main”方法

3.在“main”方法中创建一个“autoreleasepool”

4.将你的代码放在“autoreleasepool”中

取消任务:

这里关键是要经常地检查NSOperation类的isCancelled属性。

- (void)main {

    // a lengthy operation 

    @autoreleasepool {

    for (int i = 0 ; i < 10000 ; i++) {

    // is this operation cancelled?

      if (self.isCancelled)

      break;

      NSLog(@"%f", sqrt(i));

      }

    }

}

为了取消这个操作,你应该调用NSOperation的取消方法,正如下面的:

[my_lengthy_operation cancel];

从属性(Dependency):

你可以让一个操作从属于其他的操作。任何操作都可以从属于任意数量的操作。当你让操作A从属于操作B时,即使你调用了操作A的“start”方法,它会等待操作B结束后才开始执行。例如:

MyDownloadOperation *downloadOp = [[MyDownloadOperation alloc] init]; // MyDownloadOperation is a subclass of NSOperation

MyFilterOperation *filterOp = [[MyFilterOperation alloc] init]; // MyFilterOperation  is a subclass of NSOperation

[filterOp addDependency:downloadOp];

要删除依赖性:

[filterOp removeDependency:downloadOp];

优先级(Priority):

有时候你希望在后台运行的操作并不是很重要的,它可以以较低的优先级执行。可以通过使用“setQueuePriority:”方法设置一个操作的优先级。

[filterOp setQueuePriority:NSOperationQueuePriorityVeryLow];

其他关于设置线程优先级的选择有: NSOperationQueuePriorityLow, NSOperationQueuePriorityNormal, NSOperationQueuePriorityHigh和NSOperationQueuePriorityVeryHigh.

当你添加了操作到一个队列时,在对操作调用“start”方法之前,NSOperationQueue会浏览所有的操作。那些有较高优先级的操作会被先执行。有同等优先级的操作会按照添加到队列中的顺序去执行(先进先出)。

Completion block:

在NSOperation 类中另一个有用的方法叫setCompletionBlock:。一旦操作完成了,如果你还有一些事情想做,你可以把它放在一个块中,并且传递给这个方法。这个块会在主线程中执行。

你一旦添加了一个操作到一个队列(NSOperationQueue的一个实例)中,就要负责释放它(如果你不使用ARC的话)。NSOperationQueue获得操作对象的所有权,调用“start”方法,然后结束时负责释放它。

你不能重用一个操作对象。一旦它被添加到一个队列中,你就丧失了对它的所有权。如果你想再使用同一个操作类,就必须创建一个新的实例变量。

一个结束的操作不能被重启。

一个操作是否成功地完成,失败了,或者是被取消了,isFinished的值总会被设置为YES。所以千万不要觉得isFinished==YES就表示所有的事情都顺利完成了—特别的,如果你在代码里面有从属性(dependencies),就要更加注意!



NSOperationQueue

并发操作:

队列和线程是两个不同的概念。一个队列可以有多个线程。每个队列中的操作会在所属的线程中运行。举个例子你创建一个队列,然后添加三个操作到里面。队列会发起三个单独的线程,然后让所有操作在各自的线程中并发运行。

并发操作的最大值:

你可以设定NSOperationQueue可以并发运行的最大操作数。NSOperationQueue会选择去运行任何数量的并发操作,但是不会超过最大值。

myQueue.MaxConcurrentOperationCount = 3;

如果你改变了主意,想将MaxConcurrentOperationCount设置回默认值,你可以执行下列操作:

myQueue.MaxConcurrentOperationCount = NSOperationQueueDefaultMaxConcurrentOperationCount;

添加操作:

一个操作一旦被添加到一个队列中,你就应该通过传送一个release消息给操作对象(如果使用了手动引用计数,非ARC的话),然后队列会负责开始这个操作。从这点上看,什么时候调用“start”方法由这个队列说了算。

[myQueue addOperation:downloadOp];

[downloadOp release]; // manual reference counting

待处理的操作:

任何时候你可以询问一个队列哪个操作在里面,并且总共有多少个操作在里面。记住只有那些等待被执行的操作,还有那些正在运行的操作,会被保留在队列中。操作一完成,就会退出队列。

NSArray *active_and_pending_operations = myQueue.operations;

NSInteger count_of_operations = myQueue.operationCount;

暂停队列:

你可以通过设定setSuspended:YES来暂停一个队列。这样会暂停所有在队列中的操作 — 你不能单独的暂停操作。要重新开始队列,只要简单的setSuspended:NO。

// Suspend a queue

[myQueue setSuspended:YES];

取消操作:

要取消一个队列中的所有操作,你只要简单的调用“cancelAllOperations”方法即可。还记得之前提醒过经常检查NSOperation中的isCancelled属性吗?

原因是“cancelAllOperations”并没有做太多的工作,他只是对队列中的每一个操作调用“cancel”方法 — 这并没有起很大作用!:] 如果一个操作并没有开始,然后你对它调用“cancel”方法,操作会被取消,并从队列中移除。然而,如果一个操作已经在执行了,这就要由单独的操作去识别撤销(通过检查isCancelled属性)然后停止它所做的工作。

[myQueuecancelAllOperations];

addOperationWithBlock: 

如果你有一个简单的操作不需要被继承,你可以将它当做一个块(block)传递给队列。如果你需要从块那里传递回任何数据,记得你不应该传递任何强引用的指针给块;相反,你必须使用弱引用。而且,如果你想要在块中做一些跟UI有关的事情,你必须在主线程中做。

UIImage *myImage = nil;

// Create a weak reference

__weak UIImage *myImage_weak = myImage;

// Add an operation as a block to a queue

[myQueue addOperationWithBlock: ^ {

// a block of operation

NSURL *aURL = [NSURL URLWithString:@"http://www.somewhere.com/image.png"];

NSError *error = nil;

NSData *data = [NSData dataWithContentsOfURL:aURL options:nil error:&error];

If (!error)

[myImage_weak imageWithData:data];

// Get hold of main queue (main thread)

[[NSOperationQueue mainQueue] addOperationWithBlock: ^ {

myImageView.image = myImage_weak; // updating UI

}];

}];

你可能感兴趣的:(NSOperation和NSOperationQueue)