簡(jiǎn)介
在iOS中厨喂,我們需要將非UI且耗時(shí)的任務(wù)放在主線程當(dāng)中執(zhí)行蜕煌,同時(shí)確保在任務(wù)完成時(shí)進(jìn)行回調(diào)斜纪。常用的三種實(shí)現(xiàn)多線程方式如下:
1. GCD
2. NSThread
3. NSOperation / NSOperationQueue
先就GCD小結(jié)下盒刚。
小結(jié)分析
下面分別予以簡(jiǎn)單小結(jié)因块。
一 GCD
GCD 是Grand Central Dispatch的縮寫籍铁,是蘋果提供的基于block回調(diào)的多線程實(shí)現(xiàn)方式。
GCD維護(hù)線程的創(chuàng)建和調(diào)度及生命周期芋酌,程序員只需負(fù)責(zé)進(jìn)行業(yè)務(wù)邏輯的處理脐帝。
GCD有異步和同步執(zhí)行任務(wù)兩種處理方式.使用時(shí)腮恩,無(wú)須關(guān)心隊(duì)列和任務(wù)的調(diào)度温兼,由系統(tǒng)負(fù)責(zé)安排募判。相應(yīng)的API函數(shù)定義在dispatch/queue.h當(dāng)中届垫。
根據(jù)該文檔中的注釋:
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.
*/
系統(tǒng)維護(hù)一個(gè)FIFO(先進(jìn)先出順序)的隊(duì)列误债,提交到隊(duì)列中的block任務(wù)由系統(tǒng)負(fù)責(zé)分配線程執(zhí)行寝蹈,但不能保證哪個(gè)線程會(huì)執(zhí)行登淘,且多個(gè)線程中只有一個(gè)保證在執(zhí)行黔州。當(dāng)系統(tǒng)中線程數(shù)不夠時(shí)流妻,將自動(dòng)創(chuàng)建線程绅这。block為空時(shí),對(duì)應(yīng)的線程會(huì)自動(dòng)被銷毀峭判。
dispatch通過(guò)dispatch_retain() 和dispatch_release()來(lái)進(jìn)行引用記數(shù)管理林螃。
(一)GCD的調(diào)用:
1.異步調(diào)用:
1.1?
void dispatch_async(dispatch_queue_tqueue,dispatch_block_tblock);
調(diào)用之后疗认,會(huì)立即返回横漏,不等待提交的block執(zhí)行完成缎浇。
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素跺,詳見(jiàn)How to use dispatch_async_f
2. 同步調(diào)用:
2.1 void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
將block中的任務(wù)執(zhí)行完成后才會(huì)返回指厌。通常用于設(shè)置和與服務(wù)器同步踩验,等待設(shè)置完成和服務(wù)器返回后才進(jìn)行下一步操作箕憾。
/*!
* @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. 多次調(diào)用
3.1 void dispatch_apply(size_titerations,dispatch_queue_tqueue, void(^block)(size_t));
函數(shù)原型如下:
/*!
* @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的隊(duì)列
GCD中有3個(gè)隊(duì)列:
2.1 主隊(duì)列
dispatch_get_main_queue(void)
主隊(duì)列一般進(jìn)行UI線程操作,及與用戶交互刻像。因此细睡,對(duì)于長(zhǎng)時(shí)間的復(fù)雜邏輯處理任務(wù),一般都將放到后臺(tái)隊(duì)列當(dāng)中進(jìn)行犀填。為了操作流暢和用戶體驗(yàn)九巡,網(wǎng)絡(luò)請(qǐng)求及數(shù)據(jù)庫(kù)操作等任務(wù)蹂季,都不要在主隊(duì)列當(dāng)中進(jìn)行偿洁。
/*!
* @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 串行隊(duì)列
創(chuàng)建:
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的隊(duì)列:
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 全局隊(duì)列
dispatch_get_global_queue(long identifier, unsigned long flags);
identifier表示優(yōu)先級(jí):有四個(gè)值:
DISPATCH_QUEUE_PRIORITY_HIGH:? ? ? ? 高優(yōu)先級(jí)宾肺,一般是需要處理的緊急任務(wù)或UI線程
?DISPATCH_QUEUE_PRIORITY_DEFAULT: ? ? ?默認(rèn)優(yōu)先級(jí)
DISPATCH_QUEUE_PRIORITY_LOW: ? ? ? ? ?低優(yōu)先級(jí)
?DISPATCH_QUEUE_PRIORITY_BACKGROUND:后臺(tái)進(jìn)程爱榕,比如網(wǎng)絡(luò)或數(shù)據(jù)庫(kù)請(qǐng)求
flags為保留值,一般設(shè)為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);
另外跪者,調(diào)試和打日志時(shí),需要用到
dispatch_queue_t dispatch_get_current_queue(void);
函數(shù)得到當(dāng)前隊(duì)列逗概。
線程延時(shí)執(zhí)行:可以使用
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