這是一篇我關(guān)于 GCD 的使用以及學習的總結(jié)文章。持續(xù)更新。
感謝諸多大神在此之前寫的各類文章,如果可以,我會盡量把他們添加到附錄中,如有遺漏,感謝提醒補充和討論。
2016-08-06
成果
假如你對我的廢話沒興趣,那么看到這里就夠了。這是我存在 GitHub 上的代碼文件,假如鏈接失效,你可以給我留言。
GCD.swift
為何 GCD
我在工作中經(jīng)常使用 GCD,因為我感覺這樣的代碼更加直接了當,如果不是必要情況,我甚至不愿意使用 NSThread,NSOperationQueue,當然,有時候,這是一種非常折騰的癖好。
總之,這些都是多線程管理工具,如果你有興趣,簡書上有非常簡單易懂的資料。稍微搜索一下即可。
至于好處,我只說一點。
這是 iOS 提供的最底層的多線程接口。
基礎(chǔ)概念
--> 名詞解釋
- Block 任務(wù):具體要執(zhí)行的工作內(nèi)容
- Queue 隊列:一個用于放置 Block 的隊伍,一個 Queue 中會有多個 Block。
- Concurrent 并發(fā):Queue 執(zhí)行自己的 Block 的方式,并發(fā)表示會有多個 Block 同時運行。
- Serial 串行:Queue 執(zhí)行自己的 Block 的方式,串行表示所有 Block 會依次按順序一個運行完才運行下一個。
- sync 同步:不會開啟新線程,堵塞當前線程來執(zhí)行
- async 異步:開啟新線程,不堵塞當前線程
- Thread 線程:程序中執(zhí)行代碼的通道,Queue 會把 Block 傳遞到這里來進行運行。
-
Process 進程:一個程序為一個進程,一個運行的 App 即是 iOS 系統(tǒng)當中運行的一個進程,一個進行可以有多個線程。
我在練英語……所以別問我為什么不做中文。
--> GCD 變量
---> dispatch_queue_t:隊列
func TestGCD() {
var queue: dispatch_queue_t
// 創(chuàng)建串行隊列
queue = dispatch_queue_create("A Serial Queue", DISPATCH_QUEUE_SERIAL)
// 創(chuàng)建并行隊列
queue = dispatch_queue_create("A Concurrent", DISPATCH_QUEUE_CONCURRENT)
// 獲取程序主隊列
queue = dispatch_get_main_queue()
// 獲取程序全局隊列
queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
}
---> dispatch_source_t: GCD 基礎(chǔ)數(shù)據(jù)類型
官方解釋:GCD provides a suite of dispatch sources—interfaces for monitoring (low-level system objects such as Unix descriptors, Mach ports, Unix signals, VFS nodes, and so forth) for activity. and submitting event handlers to dispatch queues when such activity occurs. When an event occurs, the dispatch source submits your task code asynchronously to the specified dispatch queue for processing.
翻譯:GCD 提供一個系列的調(diào)度源接口用來監(jiān)聽活動(底層的系統(tǒng)對象:例如 Unix 描述符,Mach 端口,Unix 信號,VFS 節(jié)點等等)。并且在活動發(fā)生的時候發(fā)送事件句柄給調(diào)度的隊列。當一個事件發(fā)生的時候,發(fā)送源派遣你的任務(wù)代碼到指定的派遣隊列中異步執(zhí)行。
--> GCD 方法
---> 基礎(chǔ)方法
----> dispatch_sync(queue: dispatch_queue_t, block: dispatch_block_t)
func TestGCD() {
// dispatch_sync(queue: dispatch_queue_t, block: dispatch_block_t)
// 同步執(zhí)行方法,會堵塞當前的線程,然后把該任務(wù)完成后才繼續(xù)當前線程。
// 注意:如果在 main_queue 中 dispatch_sync(queue: main_queue, block: {}) 會導(dǎo)致死鎖
print("Test Start in \(NSThread.currentThread()).")
for i in 0 ..< 10 {
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
print("Test \(i) Run in \(NSThread.currentThread()).")
}
}
print("Test End in \(NSThread.currentThread()).")
}
/* 運行結(jié)果
Test Start in <NSThread: 0x7fa490504cb0>{number = 1, name = main}.
Test 0 Run in <NSThread: 0x7fa490504cb0>{number = 1, name = main}.
Test 1 Run in <NSThread: 0x7fa490504cb0>{number = 1, name = main}.
Test 2 Run in <NSThread: 0x7fa490504cb0>{number = 1, name = main}.
Test 3 Run in <NSThread: 0x7fa490504cb0>{number = 1, name = main}.
Test 4 Run in <NSThread: 0x7fa490504cb0>{number = 1, name = main}.
Test 5 Run in <NSThread: 0x7fa490504cb0>{number = 1, name = main}.
Test 6 Run in <NSThread: 0x7fa490504cb0>{number = 1, name = main}.
Test 7 Run in <NSThread: 0x7fa490504cb0>{number = 1, name = main}.
Test 8 Run in <NSThread: 0x7fa490504cb0>{number = 1, name = main}.
Test 9 Run in <NSThread: 0x7fa490504cb0>{number = 1, name = main}.
Test End in <NSThread: 0x7fa490504cb0>{number = 1, name = main}.
*/
----> dispatch_async(queue: dispatch_queue_t, block: dispatch_block_t)
func TestGCD() {
// dispatch_async(queue: dispatch_queue_t, block: dispatch_block_t)
// 異步執(zhí)行方法,不會堵塞當前的線程,但是運行順序?qū)⒉豢煽亍?
print("Test Start in \(NSThread.currentThread()).")
for i in 0 ..< 10 {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
print("Test \(i) Run in \(NSThread.currentThread()).")
}
}
print("Test End in \(NSThread.currentThread()).")
}
/* 運行結(jié)果
Test Start in <NSThread: 0x7fbe33c09bf0>{number = 1, name = main}.
Test End in <NSThread: 0x7fbe33c09bf0>{number = 1, name = main}.
Test 2 Run in <NSThread: 0x7fbe33e0b360>{number = 2, name = (null)}.
Test 0 Run in <NSThread: 0x7fbe33f018d0>{number = 3, name = (null)}.
Test 8 Run in <NSThread: 0x7fbe33e0b360>{number = 2, name = (null)}.
Test 1 Run in <NSThread: 0x7fbe33e0cf90>{number = 4, name = (null)}.
Test 3 Run in <NSThread: 0x7fbe33f05c90>{number = 5, name = (null)}.
Test 4 Run in <NSThread: 0x7fbe33f05880>{number = 6, name = (null)}.
Test 5 Run in <NSThread: 0x7fbe33d1dc60>{number = 7, name = (null)}.
Test 6 Run in <NSThread: 0x7fbe33d09660>{number = 8, name = (null)}.
Test 7 Run in <NSThread: 0x7fbe33f04cf0>{number = 9, name = (null)}.
Test 9 Run in <NSThread: 0x7fbe33f018d0>{number = 3, name = (null)}.
*/
---> dispatch_source_t 方法
----> dispatch_source_t dispatch_source_create( dispatch_source_type_t type, uintptr_t handle, unsigned long mask, dispatch_queue_t queue)
Creates a new dispatch source to monitor low-level system objects and automatically submit a handler block to a dispatch queue in response to events.
創(chuàng)建一個新的調(diào)度源來監(jiān)聽底層系統(tǒng)對象并在響應(yīng)事件的時候自動提交處理塊給派遣隊列。
- type:源處理事件類型
- DISPATCH_SOURCE_TYPE_DATA_ADD:自定義的事件,變量增加
- DISPATCH_SOURCE_TYPE_DATA_OR:自定義的事件,變量OR
- DISPATCH_SOURCE_TYPE_MACH_SEND:MACH端口發(fā)送
- DISPATCH_SOURCE_TYPE_MACH_RECV:MACH端口接收
- DISPATCH_SOURCE_TYPE_PROC:進程監(jiān)聽,如進程的退出、創(chuàng)建一個或更多的子線程、進程收到UNIX信號
- DISPATCH_SOURCE_TYPE_READ:IO操作,如對文件的操作、socket操作的讀響應(yīng)
- DISPATCH_SOURCE_TYPE_SIGNAL:接收到UNIX信號時響應(yīng)
- DISPATCH_SOURCE_TYPE_TIMER:定時器
- DISPATCH_SOURCE_TYPE_VNODE:文件狀態(tài)監(jiān)聽,文件被刪除、移動、重命名
- DISPATCH_SOURCE_TYPE_WRITE:IO操作,如對文件的操作、socket操作的寫響應(yīng)
- handle:句柄、索引或id,假如要監(jiān)聽進程,需要傳入進程的ID
- mask:可以理解為描述,提供更詳細的描述,讓它知道具體要監(jiān)聽什么
- queue:自定義源需要的一個隊列,用來處理所有的響應(yīng)句柄(block)
// 在主隊列中創(chuàng)建一個定時器
var timer: dispatch_source_t = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue())
// 創(chuàng)建 計時器 dispatch_source_t
var source: dispatch_source_t? = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue())
// 計數(shù)
var sourceTimes = 10
//
func TestGCD() {
// 設(shè)置 dispatch_source_t 為從現(xiàn)在開始每秒調(diào)用一次
dispatch_source_set_timer(source!, dispatch_walltime(nil, 0), NSEC_PER_SEC, 0)
// 設(shè)置調(diào)用時的處理
dispatch_source_set_event_handler(source!) {
// 打印當前線程,以及計數(shù)值,然后減1.
print("\(self.sourceTimes): \(NSThread.currentThread())")
self.sourceTimes -= 1
// 如果計數(shù)結(jié)束則 釋放 或 cancel, 都會導(dǎo)致停止,但是釋放不會調(diào)用 cancel handler
if self.sourceTimes <= 0 {
//self.source = nil
dispatch_source_cancel(self.source!)
}
}
// 調(diào)用 cancel 的時候的處理
dispatch_source_set_cancel_handler(source!) {
print("source Cancel: \(NSThread.currentThread())")
self.source = nil
}
// 啟動 source 監(jiān)聽
dispatch_resume(source!)
}
----> void dispatch_source_set_timer( dispatch_source_t source, dispatch_time_t start, uint64_t interval, uint64_t leeway) 設(shè)置計時器時間
Sets a start time, interval, and leeway value for a timer source.
設(shè)置計時器源的起始時間、 間隔和回旋余地值。
----> dispatch_time_t dispatch_walltime( const struct timespec *when, int64_t delta)
Creates a dispatch_time_t using an absolute time according to the wall clock.
根據(jù)掛鐘來創(chuàng)建一個絕對事件。
- when:A struct timespec to add time to. If NULL is passed, then this function uses the result of gettimeofday.
- delta:Nanoseconds to add.
----> dispatch_time_t dispatch_time( dispatch_time_t when, int64_t delta);
Parameters
Creates a dispatch_time_t relative to the default clock or modifies an existing dispatch_time_t.
根據(jù)默認的時鐘創(chuàng)建一個 dispatch_time_t 或修改一個現(xiàn)有的 dispatch_time_t
- when:The dispatch_time_t value to use as the basis for a new value. Pass DISPATCH_TIME_NOW to create a new time value relative to now.
- delta:The number of nanoseconds to add to the time in the when parameter.
參考文獻
- 黑幕居士 -> iOS編程--GCD相關(guān)(進程、線程/多線程、并行/串行隊列、同步/異步任務(wù))
- John_LS -> IOS dispatch source 學習篇
- 未之 -> iOS多線程——Dispatch Source
我的 GitHub 空間:Myron Work Space
