談起iOS的dispatch(正式稱謂是Grand Central Dispatch或GCD),不得不說這又是iOS(包括MacOSX)平台的創新,優缺點這里不討論,只有當你使用時才能真正體會到。我們說dispatch函數的主要目的是實現多任務並發代碼,那么要理解dispatch函數,先來了解dispatch對象的定義。
dispatch對象類型的部分定義,主要使用C語言的宏定義:
<os/object.h>文件:
#define OS_OBJECT_CLASS(name) OS_##name
#define OS_OBJECT_DECL(name, ...) \
@protocol OS_OBJECT_CLASS(name) __VA_ARGS__ \
@end \
typedef NSObject<OS_OBJECT_CLASS(name)> *name##_t
#define OS_OBJECT_DECL_SUBCLASS(name, super) \
OS_OBJECT_DECL(name, <OS_OBJECT_CLASS(super)>)
<dispatch/object.h>文件:
#define DISPATCH_DECL(name) OS_OBJECT_DECL_SUBCLASS(name, dispatch_object)
#define DISPATCH_GLOBAL_OBJECT(type, object) ((OS_OBJECT_BRIDGE type)&(object))
OS_OBJECT_DECL(dispatch_object); //定義dispatch_object_t
<dispatch/queue.h>文件(dispatch隊列類定義,其它dispatch對象類似):
DISPATCH_DECL(dispatch_queue); //定義dispatch_queue_t
可以通過Xcode預編譯后可以看到最終結果,最終定義的都是NSObject類,雖然它們之間沒用直接繼承關系,但都實現OS_dispatch_object接口,這樣dispatch_queue_t對象也同樣是dispatch_object_t的對象了。下面就是預編譯dispatch_object_t和dispatch_queue_t的結果:
@protocol OS_dispatch_object
@end
typedef NSObject<OS_dispatch_object> *dispatch_object_t;
@protocol OS_dispatch_queue <OS_dispatch_object>
@end
typedef NSObject<OS_dispatch_queue> *dispatch_queue_t;
由於dispatch api接口定義成C函數的形式,dispatch的對象都是由C函數形式的廠方法得到(不能繼承dispatch類,不用alloc),這樣做隱藏dispatch對象的具體形態,把注意力放在如何調用dispatch api上。
從上面dispatch對象宏定義可以看到dispatch對象類的名稱一般為dispatch_xyz_t(嚴格來講是對象指針),它們都可以看成dispatch_object_t的子類(對象指針),所以使用dispatch對象時套用這個概念就行。
有關dispatch對象的基本接口如下:
void dispatch_retain(dispatch_object_t object); //替代dispatch對象常規的retain來持有對象,但ARC編程中不再允許
void dispatch_release(dispatch_object_t object); //替代dispatch對象常規的release來釋放對象,同樣ARC編程中不再允許
void dispatch_set_context(dispatch_object_t object, void *context); //給dispatch對象綁定特定數據對象(類似線程的TLS數據),會被傳給dispatch對象的finalizer函數
void *dispatch_get_context(dispatch_object_t object); //返回dispatch對象綁定的數據對象指針
void dispatch_set_finalizer_f(dispatch_object_t object, dispatch_function_t finalizer); //設置dispatch對象的finalizer函數,當該對象釋放時會調用finalizer,部分代碼解釋如何使用這個函數(ARC模式):
dispatch_object_t dispatchObject = ...;
void *context = ...;
dispatch_set_context(dispatchObject, context);
dispatch_set_finalizer_f(dispatchObject, finalizer);
......
dispatchObject = nil; //dispatchObject被釋放,這時調用finalizer函數
......
void finalizer(void *context)
{
//處理或釋放context相關資源
}
dispatch對象的另外兩個接口是:
void dispatch_resume(dispatch_object_t object); //激活(啟動)在dispatch對象上的block調用,可以運行多個block
void dispatch_suspend(dispatch_object_t object); //掛起(暫停)在dispatch對象上的block調用,已經運行的block不會停止
一般這兩個函數的調用必須成對,否則運行會出現異常。
至此你是否發現這兩個函數有些與眾不同呢?好像從來沒有這么使用對象的,啟動對象--暫停對象,呵呵。這正是理解dispatch對象的關鍵所在。dispatch對象其實是抽象的任務,把動態的任務變成對象來管理。任務是動態的,不存在繼承關系,這就是為什么GCD沒有提供靜態繼承dispatch對象類的方式。如果能這樣理解,那么在使用dispatch函數時就能夠更靈活地去編寫代碼,實現各種並發的多任務代碼。