IOS Dispatch Source 筆記

代碼地址(僅供參考)

現代系統通常提供異步接口,允許應用向系統提交請求,然后在系統處理請 求時應用可以繼續處理其他事情。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一般步驟
  1. 使用dispatch_source_create創建dispatch source
  2. 配置dispatch source:
    • 設置一個事件處理器
    • 如果是定時器源,使用dispatch_source_set_timer函數設置定時器信息
  3. 為dispatch source賦予一個取消處理器(可選)
  4. 調用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;
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Dispatch Sources 現代系統通常提供異步接口,允許應用向系統提交請求,然后在系統處理請求時應用可以繼...
    好雨知時節浩宇閱讀 3,838評論 2 5
  • 支持原創 現代系統通常提供異步接口,允許應用向系統提交請求,然后在系統處理請求時應用可以繼續處理自己的事情。Gra...
    John_LS閱讀 3,605評論 3 2
  • 關于Dispatch Source Dispatch Source是GCD中的一種基本數據類型,從字面意思可稱其為...
    杭研融合通信iOS閱讀 3,643評論 1 9
  • Dispatch Sources 現代系統通常提供異步接口,允許應用向系統提交請求,然后在系統處理請求時應用可以繼...
    YangPu閱讀 332評論 0 0
  • 如果可以的話,我只想隨便一間屋子,獨自呆著。想去哪里去哪里。 我明明喜歡的是到處走,為什么要固定在一個地方。我喜歡...
    明天飛閱讀 143評論 0 0