简介
在iOS中,我们需要将非UI且耗时的任务放在主线程当中执行,同时确保在任务完成时进行回调。常用的三种实现多线程方式如下:
1. GCD
2. NSThread
3. NSOperation / NSOperationQueue
先就GCD小结下。
小结分析
下面分别予以简单小结。
一 GCD
GCD 是Grand Central Dispatch的缩写,是苹果提供的基于block回调的多线程实现方式。
GCD维护线程的创建和调度及生命周期,程序员只需负责进行业务逻辑的处理。
GCD有异步和同步执行任务两种处理方式.使用时,无须关心队列和任务的调度,由系统负责安排。相应的API函数定义在dispatch/queue.h当中。
根据该文档中的注释:
Dispatch is an abstract model for expressing concurrency via simple but
powerful API.
*
* At the core, dispatch provides serial FIFO queues to which blocks may be
* submitted. Blocks submitted to these dispatch queues are invoked on a pool
* of threads fully managed by the system. No guarantee is made regarding
* which thread a block will be invoked on; however, it is guaranteed that only
* one block submitted to the FIFO dispatch queue will be invoked at a time.
*
* When multiple queues have blocks to be processed, the system is free to
* allocate additional threads to invoke the blocks concurrently. When the
* queues become empty, these threads are automatically released.
/*!
* @typedef dispatch_queue_t
*
* @abstract
* Dispatch queues invoke blocks submitted to them serially in FIFO order. A
* queue will only invoke one block at a time, but independent queues may each
* invoke their blocks concurrently with respect to each other.
*
* @discussion
* Dispatch queues are lightweight objects to which blocks may be submitted.
* The system manages a pool of threads which process dispatch queues and
* invoke blocks submitted to them.
*
* Conceptually a dispatch queue may have its own thread of execution, and
* interaction between queues is highly asynchronous.
*
* Dispatch queues are reference counted via calls to dispatch_retain() and
* dispatch_release(). Pending blocks submitted to a queue also hold a
* reference to the queue until they have finished. Once all references to a
* queue have been released, the queue will be deallocated by the system.
*/
系统维护一个FIFO(先进先出顺序)的队列,提交到队列中的block任务由系统负责分配线程执行,但不能保证哪个线程会执行,且多个线程中只有一个保证在执行。当系统中线程数不够时,将自动创建线程。block为空时,对应的线程会自动被销毁。
dispatch通过dispatch_retain() 和dispatch_release()来进行引用记数管理。
(一)GCD的调用:
1.异步调用:
1.1
void dispatch_async(dispatch_queue_tqueue,dispatch_block_tblock);
调用之后,会立即返回,不等待提交的block执行完成。
1.2
void dispatch_async_f(dispatch_queue_tqueue,
void*context,
dispatch_function_twork);
/*!
* @function dispatch_async_f
*
* @abstract
* Submits a function for asynchronous execution on a dispatch queue.
*
* @discussion
* See dispatch_async() for details.
*
* @param queue
* The target dispatch queue to which the function is submitted.
* The system will hold a reference on the target queue until the function
* has returned.
* The result of passing NULL in this parameter is undefined.
*
* @param context
* The application-defined context parameter to pass to the function.
*
* @param work
* The application-defined function to invoke on the target queue. The first
* parameter passed to this function is the context provided to
* dispatch_async_f().
* The result of passing NULL in this parameter is undefined.
*/
__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)
DISPATCH_EXPORTDISPATCH_NONNULL1DISPATCH_NONNULL3DISPATCH_NOTHROW
void
dispatch_async_f(dispatch_queue_tqueue,
void*context,
dispatch_function_twork);
context可以传0或Nsnull,详见How to use dispatch_async_f
2. 同步调用:
2.1 void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
将block中的任务执行完成后才会返回。通常用于设置和与服务器同步,等待设置完成和服务器返回后才进行下一步操作。
/*!
* @function dispatch_sync
*
* @abstract
* Submits a block for synchronous execution on a dispatch queue.
*
* @discussion
* Submits a block to a dispatch queue like dispatch_async(), however
* dispatch_sync() will not return until the block has finished.
*
* Calls to dispatch_sync() targeting the current queue will result
* in dead-lock. Use of dispatch_sync() is also subject to the same
* multi-party dead-lock problems that may result from the use of a mutex.
* Use of dispatch_async() is preferred.
*
* Unlike dispatch_async(), no retain is performed on the target queue. Because
* calls to this function are synchronous, the dispatch_sync() "borrows" the
* reference of the caller.
*
* As an optimization, dispatch_sync() invokes the block on the current
* thread when possible.
*
* @param queue
* The target dispatch queue to which the block is submitted.
* The result of passing NULL in this parameter is undefined.
*
* @param block
* The block to be invoked on the target dispatch queue.
* The result of passing NULL in this parameter is undefined.
*/
#ifdef __BLOCKS__
__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)
DISPATCH_EXPORT DISPATCH_NONNULL_ALL DISPATCH_NOTHROW
void
dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
#endif
2.2 void dispatch_sync_f(dispatch_queue_t queue,
void *context,
dispatch_function_t work);
/*!
* @function dispatch_sync_f
*
* @abstract
* Submits a function for synchronous execution on a dispatch queue.
*
* @discussion
* See dispatch_sync() for details.
*
* @param queue
* The target dispatch queue to which the function is submitted.
* The result of passing NULL in this parameter is undefined.
*
* @param context
* The application-defined context parameter to pass to the function.
*
* @param work
* The application-defined function to invoke on the target queue. The first
* parameter passed to this function is the context provided to
* dispatch_sync_f().
* The result of passing NULL in this parameter is undefined.
*/
__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)
DISPATCH_EXPORT DISPATCH_NONNULL1 DISPATCH_NONNULL3 DISPATCH_NOTHROW
void
dispatch_sync_f(dispatch_queue_t queue,
void *context,
dispatch_function_t work);
3. 多次调用
3.1 void dispatch_apply(size_titerations,dispatch_queue_tqueue, void(^block)(size_t));
函数原型如下:
/*!
* @function dispatch_apply
*
* @abstract
* Submits a block to a dispatch queue for multiple invocations.
*
* @discussion
* Submits a block to a dispatch queue for multiple invocations. This function
* waits for the task block to complete before returning. If the target queue
* is concurrent, the block may be invoked concurrently, and it must therefore
* be reentrant safe.
*
* Each invocation of the block will be passed the current index of iteration.
*
* @param iterations
* The number of iterations to perform.
*
* @param queue
* The target dispatch queue to which the block is submitted.
* The result of passing NULL in this parameter is undefined.
*
* @param block
* The block to be invoked the specified number of iterations.
* The result of passing NULL in this parameter is undefined.
*/
#ifdef __BLOCKS__
__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)
DISPATCH_EXPORTDISPATCH_NONNULL3DISPATCH_NOTHROW
void
dispatch_apply(size_titerations,dispatch_queue_tqueue,
void(^block)(size_t));
#endif
3.2 void dispatch_apply_f(size_titerations,dispatch_queue_tqueue,
void*context,
void(*work)(void*,size_t));
/*!
* @function dispatch_apply_f
*
* @abstract
* Submits a function to a dispatch queue for multiple invocations.
*
* @discussion
* See dispatch_apply() for details.
*
* @param iterations
* The number of iterations to perform.
*
* @param queue
* The target dispatch queue to which the function is submitted.
* The result of passing NULL in this parameter is undefined.
*
* @param context
* The application-defined context parameter to pass to the function.
*
* @param work
* The application-defined function to invoke on the target queue. The first
* parameter passed to this function is the context provided to
* dispatch_apply_f(). The second parameter passed to this function is the
* current index of iteration.
* The result of passing NULL in this parameter is undefined.
*/
__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)
DISPATCH_EXPORTDISPATCH_NONNULL4DISPATCH_NOTHROW
void
dispatch_apply_f(size_titerations,dispatch_queue_tqueue,
void*context,
void(*work)(void*,size_t));
(二)GCD的队列
GCD中有3个队列:
2.1 主队列
dispatch_get_main_queue(void)
主队列一般进行UI线程操作,及与用户交互。因此,对于长时间的复杂逻辑处理任务,一般都将放到后台队列当中进行。为了操作流畅和用户体验,网络请求及数据库操作等任务,都不要在主队列当中进行。
/*!
* @function dispatch_get_main_queue
*
* @abstract
* Returns the default queue that is bound to the main thread.
*
* @discussion
* In order to invoke blocks submitted to the main queue, the application must
* call dispatch_main(), NSApplicationMain(), or use a CFRunLoop on the main
* thread.
*
* @result
* Returns the main queue. This queue is created automatically on behalf of
* the main thread before main() is called.
*/
DISPATCH_INLINE DISPATCH_ALWAYS_INLINE DISPATCH_CONST DISPATCH_NOTHROW
dispatch_queue_t
dispatch_get_main_queue(void)
{
return DISPATCH_GLOBAL_OBJECT(dispatch_queue_t, _dispatch_main_q);
}
2.2 串行队列
创建:
dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);
/*!
* @function dispatch_queue_create
*
* @abstract
* Creates a new dispatch queue to which blocks may be submitted.
*
* @discussion
* Dispatch queues created with the DISPATCH_QUEUE_SERIAL or a NULL attribute
* invoke blocks serially in FIFO order.
*
* Dispatch queues created with the DISPATCH_QUEUE_CONCURRENT attribute may
* invoke blocks concurrently (similarly to the global concurrent queues, but
* potentially with more overhead), and support barrier blocks submitted with
* the dispatch barrier API, which e.g. enables the implementation of efficient
* reader-writer schemes.
*
* When a dispatch queue is no longer needed, it should be released with
* dispatch_release(). Note that any pending blocks submitted to a queue will
* hold a reference to that queue. Therefore a queue will not be deallocated
* until all pending blocks have finished.
*
* Passing the result of the dispatch_queue_attr_make_with_qos_class() function
* to the attr parameter of this function allows a quality of service class and
* relative priority to be specified for the newly created queue.
* The quality of service class so specified takes precedence over the quality
* of service class of the newly created dispatch queue's target queue (if any)
* as long that does not result in a lower QOS class and relative priority.
*
* When no quality of service class is specified, the target queue of a newly
* created dispatch queue is the default priority global concurrent queue.
*
* @param label
* A string label to attach to the queue.
* This parameter is optional and may be NULL.
*
* @param attr
* DISPATCH_QUEUE_SERIAL, DISPATCH_QUEUE_CONCURRENT, or the result of a call to
* the function dispatch_queue_attr_make_with_qos_class().
*
* @result
* The newly created dispatch queue.
*/
__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)
DISPATCH_EXPORT DISPATCH_MALLOC DISPATCH_RETURNS_RETAINED DISPATCH_WARN_RESULT
DISPATCH_NOTHROW
dispatch_queue_t
dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);
获取指定label的队列:
const char *dispatch_queue_get_label(dispatch_queue_t queue);
/*!
* @function dispatch_queue_get_label
*
* @abstract
* Returns the label of the given queue, as specified when the queue was
* created, or the empty string if a NULL label was specified.
*
* Passing DISPATCH_CURRENT_QUEUE_LABEL will return the label of the current
* queue.
*
* @param queue
* The queue to query, or DISPATCH_CURRENT_QUEUE_LABEL.
*
* @result
* The label of the queue.
*/
__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)
DISPATCH_EXPORT DISPATCH_PURE DISPATCH_WARN_RESULT DISPATCH_NOTHROW
const char *
dispatch_queue_get_label(dispatch_queue_t queue);
2.3 全局队列
dispatch_get_global_queue(long identifier, unsigned long flags);
identifier表示优先级:有四个值:
DISPATCH_QUEUE_PRIORITY_HIGH: 高优先级,一般是需要处理的紧急任务或UI线程
DISPATCH_QUEUE_PRIORITY_DEFAULT: 默认优先级
DISPATCH_QUEUE_PRIORITY_LOW: 低优先级
DISPATCH_QUEUE_PRIORITY_BACKGROUND:后台进程,比如网络或数据库请求
flags为保留值,一般设为0.
/*!
* @function dispatch_get_global_queue
*
* @abstract
* Returns a well-known global concurrent queue of a given quality of service
* class.
*
* @discussion
* The well-known global concurrent queues may not be modified. Calls to
* dispatch_suspend(), dispatch_resume(), dispatch_set_context(), etc., will
* have no effect when used with queues returned by this function.
*
* @param identifier
* A quality of service class defined in qos_class_t or a priority defined in
* dispatch_queue_priority_t.
*
* It is recommended to use quality of service class values to identify the
* well-known global concurrent queues:
* - QOS_CLASS_USER_INTERACTIVE
* - QOS_CLASS_USER_INITIATED
* - QOS_CLASS_DEFAULT
* - QOS_CLASS_UTILITY
* - QOS_CLASS_BACKGROUND
*
* The global concurrent queues may still be identified by their priority,
* which map to the following QOS classes:
* - DISPATCH_QUEUE_PRIORITY_HIGH: QOS_CLASS_USER_INITIATED
* - DISPATCH_QUEUE_PRIORITY_DEFAULT: QOS_CLASS_DEFAULT
* - DISPATCH_QUEUE_PRIORITY_LOW: QOS_CLASS_UTILITY
* - DISPATCH_QUEUE_PRIORITY_BACKGROUND: QOS_CLASS_BACKGROUND
*
* @param flags
* Reserved for future use. Passing any value other than zero may result in
* a NULL return value.
*
* @result
* Returns the requested global queue or NULL if the requested global queue
* does not exist.
*/
__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)
DISPATCH_EXPORT DISPATCH_CONST DISPATCH_WARN_RESULT DISPATCH_NOTHROW
dispatch_queue_t
dispatch_get_global_queue(long identifier, unsigned long flags);
另外,调试和打日志时,需要用到
dispatch_queue_t dispatch_get_current_queue(void);
函数得到当前队列。
线程延时执行:可以使用
void dispatch_after(dispatch_time_t when,
dispatch_queue_t queue,
dispatch_block_t block);
/*!
* @function dispatch_after
*
* @abstract
* Schedule a block for execution on a given queue at a specified time.
*
* @discussion
* Passing DISPATCH_TIME_NOW as the "when" parameter is supported, but not as
* optimal as calling dispatch_async() instead. Passing DISPATCH_TIME_FOREVER
* is undefined.
*
* @param when
* A temporal milestone returned by dispatch_time() or dispatch_walltime().
*
* @param queue
* A queue to which the given block will be submitted at the specified time.
* The result of passing NULL in this parameter is undefined.
*
* @param block
* The block of code to execute.
* The result of passing NULL in this parameter is undefined.
*/
#ifdef __BLOCKS__
__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)
DISPATCH_EXPORT DISPATCH_NONNULL2 DISPATCH_NONNULL3 DISPATCH_NOTHROW
void
dispatch_after(dispatch_time_t when,
dispatch_queue_t queue,
dispatch_block_t block);
#endif
网友评论