現代系統通常提供異步接口,允許應用向系統提交請求,然后在系統處理請 求時應用可以繼續處理其他事情。GCD 正是基于這個基本行為而設計,允許你 提交請求,并通過 block 和 dispatch queue 報告結果,而Dispatch Source替代了異步回調函數,來處理相關事件。
根據官方文檔GCD支持以下Dispatch Source類型
DISPATCH_SOURCE_TYPE_DATA_ADD 自定義事件
DISPATCH_SOURCE_TYPE_DATA_OR 自定義事件
DISPATCH_SOURCE_TYPE_MACH_RECV 監聽MACH響應事件
DISPATCH_SOURCE_TYPE_MACH_SEND 監聽MACH響應事件
DISPATCH_SOURCE_TYPE_PROC 進程監聽(退出,創建,fork 或 exec等調用)
DISPATCH_SOURCE_TYPE_READ 文件可讀
DISPATCH_SOURCE_TYPE_WRITE 文件可寫
DISPATCH_SOURCE_TYPE_SIGNAL UNIX信號到達時時響應
DISPATCH_SOURCE_TYPE_TIMER 定時器
DISPATCH_SOURCE_TYPE_VNODE 文件狀態監聽例如移動,刪除,重命名等事件
DISPATCH_SOURCE_TYPE_MEMORYPRESSURE 監聽系統內存壓力
創建Dispatch Source一般步驟
- 使用
dispatch_source_create
創建dispatch source - 配置dispatch source:
- 設置一個事件處理器
- 如果是定時器源,使用dispatch_source_set_timer函數設置定時器信息
- 為dispatch source賦予一個取消處理器(可選)
- 調用dispatch_resume 函數開始處理事件
定時器
示例代碼:
函數會創建一個定時器
dispatch_source_t CreateDispatchTimer(uint64_t interval, uint64_t leeway,
dispatch_queue_t queue, dispatch_block_t block)
{
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
if (timer) {
dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), interval, leeway);//設置定時器信息
dispatch_source_set_event_handler(timer, block);//設置處理器
dispatch_resume(timer); //調用以便函數開始處理事件
}
return timer;
}
可捕獲的事件類型
//調用示例
dispatch_source_t source_t = CreateDispatchTimer(30ull * NSEC_PER_SEC, 1ull * NSEC_PER_SEC, dispatch_get_global_queue(0, 0), ^{
NSLog(@"executing");
});
uintptr_t handle = dispatch_source_get_handle(source_t);
unsigned long data = dispatch_source_get_data(source_t);
unsigned long mask = dispatch_source_get_mask(source_t);
NSLog(@"done");
函數 | 描述 |
---|---|
dispatch_source_get_handle | 這個函數返回 dispatch source 管理的底層系 統數據類型。 |
對于描述符 dispatch source,函數返回一個 int,表示關聯的描述符 | |
對于信號 dispatch source,函數返回一個 int 表示最新事件的信號數值 | |
對于進程 dispatch source,函數返回一個 pid_t 數據結構,表示被監控的進程 | |
對于 Mach port dispatch source,函數返回一 個 mach_port_t 數據結構 | |
對于其它 dispatch source,函數返回的值未 定義 | |
dispatch_source_get_data | 這個函數返回事件關聯的所有未決數據。 |
對于從文件中讀取數據的描述符 dispatch source,這個函數返回可以讀取的字節數 | |
對于監控文件系統活動的描述符 dispatch source,函數返回一個常量,表示發生的事 件類型,參考 dispatch_source_vnode_flags_t 枚舉類型 | |
對于進程 dispatch source,函數返回一個常 量,表示發生的事件類型,參考 dispatch_source_proc_flags_t 枚舉類型 | |
對于 Mach port dispatch source,函數返回一 個常量,表示發生的事件類型,參考dispatch_source_machport_flags_t 枚舉 類型 | |
對于自定義 dispatch source,函數返回從現 有數據創建的新數據,以及傳遞給 dispatch_source_merge_data 函數的新數 據。 | |
dispatch_source_get_mask | 這個函數返回用來創建 dispatch source 的事 件標志 |
對于進程 dispatch source,函數返回 dispatch source 接收到的事件掩碼,參考 dispatch_source_proc_flags_t 枚舉類型 | |
對于發送權利的 Mach port dispatch source, 函數返回期望事件的掩碼,參考 dispatch_source_mach_send_flags_t 枚舉 類型 | |
對于自定義 “或” 的 dispatch source,函數返 回用來合并數據值的掩碼。 |
Dispatch Source實例
- 分派源
dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD,
0, 0, dispatch_get_main_queue());
__block long totalComplete = 0;
//在同一時間,只有一個處理方法塊的實例被分派,
//如果這個處理方法還未執行完畢,另一個事件就發生了,
//事件會以指定方式(ADD 或者 OR)進行累積.
//處理時間最終執行時,計算后的數據通過dispatch_source_get_data 獲取
dispatch_source_set_event_handler(source, ^{
long value = dispatch_source_get_data(source);
totalComplete += value;
NSLog(@"totalComplete: %ld", totalComplete);
});
//恢復源
dispatch_resume(source);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0);
// 恢復源后通過 dispatch_source_merge_data 向分派源發送事件
dispatch_async(queue, ^{
for (int i = 0; i <= 100; ++i) {
dispatch_source_merge_data(source, 1);
usleep(20000);
}
});
- 定時器源
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 1 * NSEC_PER_SEC);
dispatch_source_set_event_handler(timer, ^{
//do something
});
dispatch_resume(timer);
- 從描述符中讀取數據
dispatch_source_t ReadContentsFromFile(const char* filename)
{
// 獲取文件指針
int fd = open(filename, O_RDONLY);
if (fd == -1) {//獲取失敗
return NULL;
}
// 設置文件描述符狀態旗標,防止阻塞讀取操作
fcntl(fd, F_SETFL, O_NONBLOCK);
// 獲取全局隊列,優先級默認
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t readSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, queue);
if (!readSource) {
close(fd);
return NULL;
}
// 設置事件響應
dispatch_source_set_event_handler(readSource, ^{
size_t estimatedSize = dispatch_source_get_data(readSource) + 1;
char *buffer = (char *)malloc(estimatedSize);
if (buffer) {
ssize_t actual = read(fd, buffer, (estimatedSize));
// do something with buffer
free(buffer);
//讀取完畢后
// dispatch_source_cancel(readSource);
}
});
// 取消事件
dispatch_source_set_cancel_handler(readSource, ^{close(fd);});
// 喚醒source
dispatch_resume(readSource);
return readSource;
}
- 向描述符寫入數據
dispatch_source_t WriteDataToFile(const char* filename)
{
// 獲取文件指針
int fd = open(filename);
if (fd == -1)//獲取失敗
return NULL;
// 設置文件描述符狀態標旗,讀文件時候阻塞
fcntl(fd, F_SETFL);
// 獲取全局隊列,優先級默認
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 創建source
dispatch_source_t writeSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, fd, 0, queue);
if (!writeSource) {
close(fd);
return NULL;
}
// 設置事件響應
dispatch_source_set_event_handler(writeSource, ^{
size_t estimatedSize = dispatch_source_get_data(writeSource) + 1;
char *buffer = (char *)malloc(estimatedSize);
if (buffer) {
ssize_t actual = read(fd, buffer, (estimatedSize));
// do something with buffer
free(buffer);
}
//讀取完畢后
dispatch_source_cancel(readSource);
});
// 取消事件
dispatch_source_set_cancel_handler(writeSource, ^{close(fd);});
// 喚醒source
dispatch_resume(writeSource);
return writeSource;
}
- 監控文件系統對象
dispatch_source_t MonitorFileNameChange(const char* filename)
{
// 文件只讀
int fd = open(filename, O_EVTONLY);
if (fd == -1) return NULL;//獲取失敗
// 獲取全局隊列,優先級默認
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 創建source
dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd, DISPATCH_VNODE_RENAME, queue);
if (source)
{
// 獲取文件名長度
int length = strlen(filename);
char* newString = (char*)malloc(length + 1);
newString = strcpy(newString, filename);
dispatch_set_context(source, newString);
// 設置事件響應
dispatch_source_set_event_handler(source, ^{
const char* oldFilename = (char*)dispatch_get_context(source);
// dosomething
});
// 清理操作
dispatch_source_set_cancel_handler(source, ^{
char* fileStr = (char*)dispatch_get_context(source);
free(fileStr);
close(fd);
});
// 恢復source
dispatch_resume(source);
}
return nil;
}
- 監控進程
dispatch_source_t MonitorProcess()
{
// 獲取進程pid
pid_t pid = getppid();
// 獲取全局隊列,優先級默認
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 創建source
dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC , pid, DISPATCH_PROC_EXIT, queue);
if (source)
{
dispatch_source_set_event_handler(source, ^{
// do something with process exit event
dispatch_source_cancel(source);
// dispatch_release(source);
});
dispatch_resume(source);
}
return source;
}