首页 > 代码库 > NSOperationQueue 和 NSOperation
NSOperationQueue 和 NSOperation
The NSOperationQueue
class regulates the execution of a set of NSOperation
objects. After being added to a queue, an operation remains in that queue until it is explicitly canceled or finishes executing its task. Operations within the queue (but not yet executing) are themselves organized according to priority levels and inter-operation object dependencies and are executed accordingly. An application may create multiple operation queues and submit operations to any of them.
NSOperationQueue类来控制一系列NSOperation对象的执行。当一个operation添加到队列时,这个operation会一直在队列中直到被显示的canceled或者执行完成任务。在队列中的operations(没有执行前的会根据优先级和依赖关系来执行)
Inter-operation dependencies provide an absolute execution order for operations, even if those operations are located in different operation queues. An operation object is not considered ready to execute until all of its dependent operations have finished executing. For operations that are ready to execute, the operation queue always executes the one with the highest priority relative to the other ready operations. For details on how to set priority levels and dependencies, see NSOperation Class Reference.
有依赖关系的operation提供一个序列化的操作运行。即使这些operations位于不同的operation queues中,就是说不同的operation queues间的operations也可以设定依赖关系只是不能互相依赖,比如a依赖b,不能又设定为b也依赖a。只能单向依赖。当所有其依赖的operations都执行完成后这个operation对象才准备执行。对于那些准备好执行的operations,operation queue总是首先执行优先级高的一个。如何设置优先级和依赖关系,可以查看NSOperation Class Reference。
You cannot directly remove an operation from a queue after it has been added. An operation remains in its queue until it reports that it is finished with its task. Finishing its task does not necessarily mean that the operation performed that task to completion. An operation can also be canceled. Canceling an operation object leaves the object in the queue but notifies the object that it should abort its task as quickly as possible. For currently executing operations, this means that the operation object’s work code must check the cancellation state, stop what it is doing, and mark itself as finished. For operations that are queued but not yet executing, the queue must still call the operation object’s start
method so that it can processes the cancellation event and mark itself as finished.
你不能直接删除一个队列中的operation。一个operation只有在finished后否则将一直存在于queue中。operation可以被cancel。意思是这个operation仍然在queue中但是会同志对象它应该尽快得终止其任务。对于目前正在执行的operations来说,这就意味着operation对象的work code必须检测cancellation状态。停止正在做的并且把自己标示为已经完成。对于在队列中但是还没有执行的operations来说,queue必须继续睇喔阿勇operation对象的start方法这样它就可以执行cancellation事件并且把自己标示为已经完成。
NOTE
Canceling an operation causes the operation to ignore any dependencies it may have. This behavior makes it possible for the queue to execute the operation’s start
method as soon as possible. The start
method, in turn, moves the operation to the finished state so that it can be removed from the queue.
注意:cancel一个operation会导致operation忽略掉所有的依赖关系。着就使得queue可以尽快执行operation的start方法。start方法将operation设置为finished状态然后就可以从queue中移除了。
Operation queues usually provide the threads used to run their operations. Operation queues use thelibdispatch
library (also known as Grand Central Dispatch) to initiate the execution of their operations. As a result, operations are always executed on a separate thread, regardless of whether they are designated as asynchronous or synchronous operations.
For more information about using operation queues, see Concurrency Programming Guide.
operation queues通常提供线程用于运行他们的operations。operation queues使用libdispatch库(就是所熟悉的grand central dispatch)来初始化这些operations的操作。最终,operations会总是在一个独立的线程中执行,而不用考虑他们是被设计成异步还是同步的operations。
KVO-Compliant Properties
The NSOperationQueue
class is key-value coding (KVC) and key-value observing (KVO) compliant. You can observe these properties as desired to control other parts of your application. To observe the properties, use the following key paths::
operations
- read-onlyoperationCount
- read-onlymaxConcurrentOperationCount
- readable and writablesuspended
- readable and writablename
- readable and writable
Although you can attach observers to these properties, you should not use Cocoa bindings to bind them to elements of your application’s user interface. Code associated with your user interface typically must execute only in your application’s main thread. However, KVO notifications associated with an operation queue may occur in any thread.
For more information about key-value observing and how to attach observers to an object, see Key-Value Observing Programming Guide.
NSOperationQueue类是一个key-value coding(kvc)并且key-value observing(kvo)的。可以通过一下的key paths来观察这些属性:
operations
- read-onlyoperationCount
- read-onlymaxConcurrentOperationCount
- readable and writablesuspended
- readable and writablename
- readable and writable
尽管你可以为这些属性添加observers,但是你不用使用cocoa bindings来将他们bind到你应用程序user interface的元素。user interface界面相关的执行必须只能在应用程序的main thread中执行。尽管如此但是和任何operation queue相关的kvo notifications可能发生在任何线程中。
Multicore Considerations
It is safe to use a single NSOperationQueue
object from multiple threads without creating additional locks to synchronize access to that object.
为多个线程创建一个 NSOperationQueue是安全的而不需要其他的locks当同步访问对象。
Additional Operation Queue Behaviors
An operation queue executes its queued operation objects based on their priority and readiness. If all of the queued operation objects have the same priority and are ready to execute when they are put in the queue—that is, their isReady
method returns YES
—they are executed in the order in which they were submitted to the queue. However, you should never rely on queue semantics to ensure a specific execution order of operation objects. Changes in the readiness of an operation can change the resulting execution order. If you need operations to execute in a specific order, use operation-level dependencies as defined by the NSOperation
class.
Inheritance
NSObject
NSOperationQueue
Conforms To
NSObject
Import Statement
@import Foundation;
Availability
Available in OS X v10.5 and later.
Getting Specific Operation Queues
currentQueue
mainQueue
Managing Operations in the Queue
addOperation:
addOperations:waitUntilFinished:
addOperationWithBlock:
operations
PropertyoperationCount
PropertycancelAllOperations
waitUntilAllOperationsAreFinished
Managing the Execution of Operations
qualityOfService
PropertymaxConcurrentOperationCount
PropertySuspending Operations
suspended
PropertyConfiguring the Queue
underlyingQueue
Propertyname
Property- Constants
Concurrent Operation Constants
NSOperation
The NSOperation
class is an abstract class you use to encapsulate the code and data associated with a single task. Because it is abstract, you do not use this class directly but instead subclass or use one of the system-defined subclasses (NSInvocationOperation
or NSBlockOperation
) to perform the actual task. Despite being abstract, the base implementation of NSOperation
does include significant logic to coordinate the safe execution of your task. The presence of this built-in logic allows you to focus on the actual implementation of your task, rather than on the glue code needed to ensure it works correctly with other system objects.
NSOperation类是一个抽象类你用来封装code和data。因为是抽象的,你不直接使用这个类而是需要subclass或者使用系统定义的subclasses(NSInvocationOperation
or NSBlockOperation
)来执行实际的任务。
An operation object is a single-shot object—that is, it executes its task once and cannot be used to execute it again. You typically execute operations by adding them to an operation queue (an instance of theNSOperationQueue
class). An operation queue executes its operations either directly, by running them on secondary threads, or indirectly using the libdispatch
library (also known as Grand Central Dispatch). For more information about how queues execute operations, see NSOperationQueue Class Reference.
operation对象是一个对象,只执行任务一次并且不能再次执行此任务。你只要是要将其加入到一个operation queue中去。一个operation queue直接执行它的operations,通过在次层线程运行他们或者使用libdispatch库(熟知的grand central dispatch)来间接操作。
If you do not want to use an operation queue, you can execute an operation yourself by calling its start
method directly from your code. Executing operations manually does put more of a burden on your code, because starting an operation that is not in the ready state triggers an exception. The ready
property reports on the operation’s readiness.
如果你不想使用operation queue,你可以通过调用start方法来操作一个operation。但是这样做会增加你的代码的负担,因为如果在未准备好时开启一个operation会引起异常。
Operation Dependencies
Dependencies are a convenient way to execute operations in a specific order. You can add and remove dependencies for an operation using the addDependency:
and removeDependency:
methods. By default, an operation object that has dependencies is not considered ready until all of its dependent operation objects have finished executing. Once the last dependent operation finishes, however, the operation object becomes ready and able to execute.
依赖关系是一个方便的方式来以特定顺序执行operations。你可以使用addDependency来为一个operation添加依赖或者removeDependency来移除依赖。默认的,只有当有依赖关系的其他operations 对象都执行完成了后此operation对象才被视为准备好了。一旦最后一个依赖operation完成,这个operation对象就变为准备好并且可以执行了。
The dependencies supported by NSOperation
make no distinction about whether a dependent operation finished successfully or unsuccessfully. (In other words, canceling an operation similarly marks it as finished.) It is up to you to determine whether an operation with dependencies should proceed in cases where its dependent operations were cancelled or did not complete their task successfully. This may require you to incorporate some additional error tracking capabilities into your operation objects.
KVO-Compliant Properties
The NSOperation
class is key-value coding (KVC) and key-value observing (KVO) compliant for several of its properties. As needed, you can observe these properties to control other parts of your application. To observe the properties, use the following key paths:
isCancelled
- read-onlyisAsynchronous
- read-onlyisExecuting
- read-onlyisFinished
- read-onlyisReady
- read-onlydependencies
- read-onlyqueuePriority
- readable and writablecompletionBlock
- readable and writable
Although you can attach observers to these properties, you should not use Cocoa bindings to bind them to elements of your application’s user interface. Code associated with your user interface typically must execute only in your application’s main thread. Because an operation may execute in any thread, KVO notifications associated with that operation may similarly occur in any thread.
If you provide custom implementations for any of the preceding properties, your implementations must maintain KVC and KVO compliance. If you define additional properties for your NSOperation
objects, it is recommended that you make those properties KVC and KVO compliant as well. For information on how to support key-value coding, see Key-Value Coding Programming Guide. For information on how to support key-value observing, see Key-Value Observing Programming Guide.
Multicore Considerations
The NSOperation
class is itself multicore aware. It is therefore safe to call the methods of an NSOperation
object from multiple threads without creating additional locks to synchronize access to the object. This behavior is necessary because an operation typically runs in a separate thread from the one that created and is monitoring it.
When you subclass NSOperation
, you must make sure that any overridden methods remain safe to call from multiple threads. If you implement custom methods in your subclass, such as custom data accessors, you must also make sure those methods are thread-safe. Thus, access to any data variables in the operation must be synchronized to prevent potential data corruption. For more information about synchronization, seeThreading Programming Guide.
Asynchronous Versus Synchronous Operations
If you plan on executing an operation object manually, instead of adding it to a queue, you can design your operation to execute in a synchronous or asynchronous manner. Operation objects are synchronous by default. In a synchronous operation, the operation object does not create a separate thread on which to run its task. When you call the start
method of a synchronous operation directly from your code, the operation executes immediately in the current thread. By the time the start
method of such an object returns control to the caller, the task itself is complete.
When you call the start
method of an asynchronous operation, that method may return before the corresponding task is completed. An asynchronous operation object is responsible for scheduling its task on a separate thread. The operation could do that by starting a new thread directly, by calling an asynchronous method, or by submitting a block to a dispatch queue for execution. It does not actually matter if the operation is ongoing when control returns to the caller, only that it could be ongoing.
If you always plan to use queues to execute your operations, it is simpler to define them as synchronous. If you execute operations manually, though, you might want to define your operation objects as asynchronous. Defining an asynchronous operation requires more work, because you have to monitor the ongoing state of your task and report changes in that state using KVO notifications. But defining asynchronous operations is useful in cases where you want to ensure that a manually executed operation does not block the calling thread.
When you add an operation to an operation queue, the queue ignores the value of the asynchronous
property and always calls the start
method from a separate thread. Therefore, if you always run operations by adding them to an operation queue, there is no reason to make them asynchronous.
For information on how to define both synchronous and asynchronous operations, see the subclassing notes.
Subclassing Notes
The NSOperation
class provides the basic logic to track the execution state of your operation but otherwise must be subclassed to do any real work. How you create your subclass depends on whether your operation is designed to execute concurrently or non-concurrently.
Methods to Override
For non-concurrent operations, you typically override only one method:
main
Into this method, you place the code needed to perform the given task. Of course, you should also define a custom initialization method to make it easier to create instances of your custom class. You might also want to define getter and setter methods to access the data from the operation. However, if you do define custom getter and setter methods, you must make sure those methods can be called safely from multiple threads.
If you are creating a concurrent operation, you need to override the following methods and properties at a minimum:
start
asynchronous
executing
finished
In a concurrent operation, your start
method is responsible for starting the operation in an asynchronous manner. Whether you spawn a thread or call an asynchronous function, you do it from this method. Upon starting the operation, your start
method should also update the execution state of the operation as reported by the executing
property. You do this by sending out KVO notifications for the executing
key path, which lets interested clients know that the operation is now running. Your executing
property must also provide the status in a thread-safe manner.
Upon completion or cancellation of its task, your concurrent operation object must generate KVO notifications for both the isExecuting
and isFinished
key paths to mark the final change of state for your operation. (In the case of cancellation, it is still important to update the isFinished
key path, even if the operation did not completely finish its task. Queued operations must report that they are finished before they can be removed from a queue.) In addition to generating KVO notifications, your overrides of the executing
and finished
properties should also continue to report accurate values based on the state of your operation.
For additional information and guidance on how to define concurrent operations, see Concurrency Programming Guide.
IMPORTANT
At no time in your start
method should you ever call super
. When you define a concurrent operation, you take it upon yourself to provide the same behavior that the default start
method provides, which includes starting the task and generating the appropriate KVO notifications. Your start
method should also check to see if the operation itself was cancelled before actually starting the task. For more information about cancellation semantics, see Responding to the Cancel Command.
Even for concurrent operations, there should be little need to override methods other than those described above. However, if you customize the dependency features of operations, you might have to override additional methods and provide additional KVO notifications. In the case of dependencies, this would likely only require providing notifications for the isReady
key path. Because the dependencies
property contains the list of dependent operations, changes to it are already handled by the default NSOperation
class.
Maintaining Operation Object States
Operation objects maintain state information internally to determine when it is safe to execute and also to notify external clients of the progression through the operation’s life cycle. Your custom subclasses must maintain this state information to ensure the correct execution of operations in your code. Table 1 lists the key paths associated with an operation’s states and how you should manage that key path in any custom subclasses.
Key Path | Description |
---|---|
| The In most cases, you do not have to manage the state of this key path yourself. If the readiness of your operations is determined by factors other than dependent operations, however—such as by some external condition in your program—you can provide your own implementation of the In OS X v10.6 and later, if you cancel an operation while it is waiting on the completion of one or more dependent operations, those dependencies are thereafter ignored and the value of this property is updated to reflect that it is now ready to run. This behavior gives an operation queue the chance to flush cancelled operations out of its queue more quickly. |
| The If you replace the |
| The If you replace the |
| The |
Responding to the Cancel Command
Once you add an operation to a queue, the operation is out of your hands. The queue takes over and handles the scheduling of that task. However, if you decide later that you do not want to execute the operation after all—because the user pressed a cancel button in a progress panel or quit the application, for example—you can cancel the operation to prevent it from consuming CPU time needlessly. You do this by calling the cancel
method of the operation object itself or by calling the cancelAllOperations
method of the NSOperationQueue
class.
使用cancel方法来取消单个的operation对象或者使用nsoperationqueueclass的cancelAllOperations方法。
Canceling an operation does not immediately force it to stop what it is doing. Although respecting the value in the cancelled
property is expected of all operations, your code must explicitly check the value in this property and abort as needed. The default implementation of NSOperation
includes checks for cancellation. For example, if you cancel an operation before its start
method is called, the start
method exits without starting the task.
canceling一个operation并不会立即强迫其停止任务。你的代码必须显示检查cancelled值并且如果需要的话abort。如果在一个operation执行start方法前你进行了cancel,那么start方法就会退出而不会开启task。
NOTE
In OS X v10.6, the behavior of the cancel
method varies depending on whether the operation is currently in an operation queue. For unqueued operations, this method marks the operation as finished immediately, generating the appropriate KVO notifications. For queued operations, it simply marks the operation as ready to execute and lets the queue call its start
method, which subsequently exits and results in the clearing of the operation from the queue.
You should always support cancellation semantics in any custom code you write. In particular, your main task code should periodically check the value of the cancelled
property. If the property reports the value YES
, your operation object should clean up and exit as quickly as possible. If you implement a custom start
method, that method should include early checks for cancellation and behave appropriately. Your custom start
method must be prepared to handle this type of early cancellation.
In addition to simply exiting when an operation is cancelled, it is also important that you move a cancelled operation to the appropriate final state. Specifically, if you manage the values for the finished
and executing
properties yourself (perhaps because you are implementing a concurrent operation), you must update those properties accordingly. Specifically, you must change the value returned by finished
to YES
and the value returned by executing
to NO
. You must make these changes even if the operation was cancelled before it started executing.
你必须更新状态当cancel掉一个operation时。你必须将finished置成yes并且吧executing置成no
Inheritance
NSObject
NSOperation
CKOperation
NSBlockOperation
NSInvocationOperation
Conforms To
NSObject
Import Statement
@import Foundation;
Availability
Available in OS X v10.5 and later.
Initialization
init
Available in OS X v10.5 through OS X v10.9Executing the Operation
start
main
completionBlock
PropertyCanceling Operations
cancel
Getting the Operation Status
cancelled
Propertyexecuting
Propertyfinished
Propertyconcurrent
Propertyasynchronous
Propertyready
Propertyname
PropertyManaging Dependencies
addDependency:
removeDependency:
dependencies
PropertyConfiguring the Execution Priority
qualityOfService
PropertythreadPriority
(OS X v10.10) PropertyqueuePriority
PropertyWaiting on an Operation Object
waitUntilFinished
Constants
NSOperationQueuePriority
These constants let you prioritize the order in which operations execute.
Declaration
SWIFT
enum NSOperationQueuePriority : Int { case VeryLow case Low case Normal case High case VeryHigh }
OBJECTIVE-C
typedef enum : NSInteger { NSOperationQueuePriorityVeryLow = -8, NSOperationQueuePriorityLow = -4, NSOperationQueuePriorityNormal = 0, NSOperationQueuePriorityHigh = 4, NSOperationQueuePriorityVeryHigh = 8 } NSOperationQueuePriority;
Constants
NSOperationQueuePriorityVeryLow
Operations receive very low priority for execution.
Available in OS X v10.5 and later.
NSOperationQueuePriorityLow
Operations receive low priority for execution.
Available in OS X v10.5 and later.
NSOperationQueuePriorityNormal
Operations receive the normal priority for execution.
Available in OS X v10.5 and later.
NSOperationQueuePriorityHigh
Operations receive high priority for execution.
Available in OS X v10.5 and later.
NSOperationQueuePriorityVeryHigh
Operations receive very high priority for execution.
Available in OS X v10.5 and later.
Discussion
You can use these constants to specify the relative ordering of operations that are waiting to be started in an operation queue. You should always use these constants (and not the defined value) for determining priority.
Import Statement
import Foundation
Availability
Available in OS X v10.5 and later.
Quality of Service Constants
Constants indicating the priority with which system resources are given to the operation
Declaration
OBJECTIVE-C
#define NSOperationQualityOfService NSQualityOfService #define NSOperationQualityOfServiceUserInteractive NSQualityOfServiceUserInteractive #define NSOperationQualityOfServiceUserInitiated NSQualityOfServiceUserInitiated #define NSOperationQualityOfServiceUtility NSQualityOfServiceUtility #define NSOperationQualityOfServiceBackground NSQualityOfServiceBackground
Constants
NSOperationQualityOfService
The overall type for quality-of-service constants. Do not use this macro as a value when specifying the quality of service.
Available in OS X v10.10 and later.
NSOperationQualityOfServiceUserInteractive
The operation corresponds to a graphically interactive task, involving scrolling or animation in some form. Because they are user interactive, operations with this service level are given the highest priority for any needed system resources.
Available in OS X v10.10 and later.
NSOperationQualityOfServiceUserInitiated
The operation corresponds to a task that the user initiated. Tasks with this service level are given a relatively high priority for system resources because they were initiated by the user and therefore correspond to work the user wants done soon.
Available in OS X v10.10 and later.
NSOperationQualityOfServiceUtility
The operation corresponds to tasks initiated by the app but reflecting relatively important work being done on behalf of the user. Tasks with this service level are given a medium priority for system resources.
Available in OS X v10.10 and later.
NSOperationQualityOfServiceBackground
The operation corresponds to tasks that are initiated by the app and represent noncritical tasks. Operations with this priority are given the lowest priority for system resources.
Available in OS X v10.10 and later.
NSOperationQueue 和 NSOperation