dispatch source.h

版本:iOS13.5

source.h

dispatch其他文件通道

注意:若有时handler不执行,是因为source被释放了,可以在回调中调用(void)dispatch_source_get_data(source);或设为属性@property (nonatomic, strong) dispatch_source_t *source;

索引

  • 创建一个新的调度源以监视低级系统对象,并响应事件自动将block回调提交给队列queue。
    dispatch_source_create
  • 为调度源source设置回调handler
    dispatch_source_set_event_handler
  • 为调度源source设置函数handler
    dispatch_source_set_event_handler_f
  • 为调度源source设置取消时调用的回调handler。
    dispatch_source_set_cancel_handler
  • 为调度源source设置取消时调用的函数handler。
    dispatch_source_set_cancel_handler_f
  • 异步取消调度源,以防止调用handler。
    dispatch_source_cancel
  • 返回与此调度源source关联的handle。
    dispatch_source_get_handle
  • 返回与此调度源source关联的mask。
    dispatch_source_get_mask
  • 返回调度源source的待处理数据
    dispatch_source_get_data
  • 将数据合并到调度源source中,并将handler提交到目标队列queue再执行。
    dispatch_source_merge_data
  • 设置计时器源的开始时间,间隔和回程值。
    dispatch_source_set_timer
  • 为调度源source设置激活后就调用的回调handler
    dispatch_source_set_registration_handler
  • 为调度源source设置激活后就调用的函数handler
    dispatch_source_set_registration_handler_f

详解

  • 创建一个新的调度源以监视低级系统对象,并响应事件自动将block回调提交给队列queue。
dispatch_source_t dispatch_source_create(dispatch_source_type_t type, 
      uintptr_t handle, unsigned long mask, dispatch_queue_t _Nullable queue);

该block回调通过dispatch_source_set_event_handlerdispatch_source_set_event_handler_f创建。
调度源创建后是非活跃的,设置好属性(handler, context)后需要调用dispatch_activatedispatch_resume激活后才能响应事件。激活后就不能再调用dispatch_set_target_queuedispatch_activate
type 调度源的类型
handle mask 通过type来确定相应作用
queue 将block提交到的调度队列。如果队列为DISPATCH_TARGET_QUEUE_DEFAULT,则源将block提交到默认优先级全局队列

//一个调度源,它合并​​调用dispatch_source_merge_data获得的数据,通过新增来合并数据。
//handle未使用(传0),mask未使用(传0)。
DISPATCH_SOURCE_TYPE_DATA_ADD 
//一个调度源,它合并​​调用dispatch_source_merge_data获得的数据,通过按位或来合并数据。
//handle未使用(传0),mask未使用(传0)。
DISPATCH_SOURCE_TYPE_DATA_OR
//一个调度源,它跟踪调用dispatch_source_merge_data获得的数据。
//新获得的数据值将替换尚未传递给源回调的现有数据值。数据值为0将导致不调用回调。
//handle未使用(传0),mask未使用(传0)。
DISPATCH_SOURCE_TYPE_DATA_REPLACE
//一个调度源,它为死名通知监视Mach端口(dead name notifications 只能发送不能接收的通知)
//handle 具有发送或只能发送一次(mach_port_t)的Mach端口
//mask dispatch_source_mach_send_flags_t类型 见下面
DISPATCH_SOURCE_TYPE_MACH_SEND
//一个调度源,它为未处理消息监视Mach端口。
//handle 具有接收权限(mach_port_t)的Mach端口
//mask dispatch_source_mach_recv_flags_t类型 见下面 但当前未定义宏(传0)
DISPATCH_SOURCE_TYPE_MACH_RECV
//一个调度源,它为内存压力状况变化监视系统
//handle未使用(传0)
//mask dispatch_source_memorypressure_flags_t类型  见下面
DISPATCH_SOURCE_TYPE_MEMORYPRESSURE
//一个调度源,它为dispatch_source_proc_flags_t定义的事件监视外部进程
//handle 进程标识符(pid_t)
//mask dispatch_source_proc_flags_t类型 见下面
DISPATCH_SOURCE_TYPE_PROC
//一个调度源,它为可供读取的未处理字节监视文件描述符。
//handle 文件描述符(int)
//mask未使用(传0)
DISPATCH_SOURCE_TYPE_READ
//一个调度源,它为信号监视当前进程
//handle 信号编号(int)
//mask未使用(传0)
DISPATCH_SOURCE_TYPE_SIGNAL
//一个调度源,它基于计时器提交事件处理块
//handle未使用(传0)
//mask dispatch_source_timer_flags_t类型 见下面
DISPATCH_SOURCE_TYPE_TIMER
//一个调度源,它为由dispatch_source_vnode_flags_t定义的事件监视文件描述符
//handle 文件描述符(int)
//mask dispatch_source_vnode_flags_t类型 见下面
DISPATCH_SOURCE_TYPE_VNODE
//一个调度源,它为可用缓冲区空间去写入字节而监视文件描述符
//handle 文件描述符(int)
//mask未使用(传0)
DISPATCH_SOURCE_TYPE_WRITE

//破坏与发送权限相对应的接收权限
#define DISPATCH_MACH_SEND_DEAD 0x1
dispatch_source_mach_send_flags_t

//暂无定义的宏
dispatch_source_mach_recv_flags_t

//系统内存压力状况已恢复正常
#define DISPATCH_MEMORYPRESSURE_NORMAL 0x01
//系统内存压力状况已更改为警告。
#define DISPATCH_MEMORYPRESSURE_WARN 0x02
//系统内存压力状况已变为严重。
#define DISPATCH_MEMORYPRESSURE_CRITICAL 0x04
dispatch_source_memorypressure_flags_t

//该进程已经退出
#define DISPATCH_PROC_EXIT 0x80000000
//该进程已创建一个或多个子进程
#define DISPATCH_PROC_FORK 0x40000000
//通过exec()或posix_spawn(),该进程已成为另一个可执行映像。
#define DISPATCH_PROC_EXEC 0x20000000
//Unix信号已传递到该进程。
#define DISPATCH_PROC_SIGNAL 0x08000000
dispatch_source_proc_flags_t

//系统应尽最大努力严格遵守通过dispatch_source_set_timer为计时器指定的回程值leeway
#define DISPATCH_TIMER_STRICT 0x1
dispatch_source_timer_flags_t;

//文件系统对象已从namespace中删除
#define DISPATCH_VNODE_DELETE 0x1
//文件系统对象数据已更改。
#define DISPATCH_VNODE_WRITE 0x2
//文件系统对象的大小已更改。
#define DISPATCH_VNODE_EXTEND 0x4
//文件系统对象元数据已更改
#define DISPATCH_VNODE_ATTRIB 0x8
//文件系统对象链接计数已更改。
#define DISPATCH_VNODE_LINK 0x10
//文件系统对象在namespace中被重命名。
#define DISPATCH_VNODE_RENAME 0x20
//文件系统对象被吊销
#define DISPATCH_VNODE_REVOKE 0x40
//文件系统对象已解锁。
#define DISPATCH_VNODE_FUNLOCK 0x100
dispatch_source_vnode_flags_t

例:
    dispatch_queue_t queue = dispatch_queue_create("source", DISPATCH_QUEUE_SERIAL);
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
  • 为调度源source设置回调handler
void dispatch_source_set_event_handler(dispatch_source_t source,
    dispatch_block_t _Nullable handler);

handler 提交给队列queue的回调typedef void (^dispatch_block_t)(void);

例:
    dispatch_queue_t queue = dispatch_queue_create("source", DISPATCH_QUEUE_SERIAL);
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    dispatch_source_set_event_handler(timer, ^{
        NSLog(@"11");
    });
  • 为调度源source设置函数handler
void dispatch_source_set_event_handler_f(dispatch_source_t source,
    dispatch_function_t _Nullable handler);

handler 提交给队列queue的函数typedef void (*dispatch_function_t)(void *_Nullable);
函数handler要传递的参数通过dispatch_set_context设置

例:
    dispatch_queue_t queue = dispatch_queue_create("source", DISPATCH_QUEUE_SERIAL);
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    dispatch_source_set_event_handler_f(timer, handler);

void handler(void *context) {
    NSLog(@"22");
}
  • 为调度源source设置取消时调用的回调handler。
void dispatch_source_set_cancel_handler(dispatch_source_t source,
    dispatch_block_t _Nullable handler);

handler 要提交到队列queue的回调

例:
    dispatch_queue_t queue = dispatch_queue_create("source", DISPATCH_QUEUE_SERIAL);
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    dispatch_block_t block = dispatch_block_create(DISPATCH_BLOCK_BARRIER, ^{
        NSLog(@"取消时的block");
    });
    dispatch_source_set_cancel_handler(timer, block);
  • 为调度源source设置取消时调用的函数handler。
void dispatch_source_set_cancel_handler_f(dispatch_source_t source,
    dispatch_function_t _Nullable handler);

handler 要提交到队列queue的函数
函数handler要传递的参数通过dispatch_set_context设置

    dispatch_queue_t queue = dispatch_queue_create("source", DISPATCH_QUEUE_SERIAL);
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    dispatch_source_set_cancel_handler_f(timer, handler);

void handler(void *context) {
    NSLog(@"22");
}
  • 异步取消调度源,以防止调用handler。
void dispatch_source_cancel(dispatch_source_t source);

不会取消正在运行的handler

  • 测试调度源source是否已取消。
long dispatch_source_testcancel(dispatch_source_t source);

long 如果取消,则返回非0;如果未取消,则返回0。

例:
    dispatch_queue_t queue = dispatch_queue_create("source", DISPATCH_QUEUE_SERIAL);
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    dispatch_source_set_event_handler(timer, ^{
        NSLog(@"11");
    });    
    //因为创建的timer是未激活的 需要先激活才能操作
    dispatch_activate(timer);
    dispatch_source_cancel(timer);
    long result = dispatch_source_testcancel(timer);
    NSLog(@"%ld", result);
输出:
1
  • 返回与此调度源source关联的handle。
uintptr_t dispatch_source_get_handle(dispatch_source_t source);

handle为dispatch_source_create中传入的handle

  • 返回与此调度源source关联的mask。
unsigned long dispatch_source_get_mask(dispatch_source_t source);

mask为dispatch_source_create中传入的mask

例:
    dispatch_queue_t queue = dispatch_queue_create("source", DISPATCH_QUEUE_SERIAL);
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 1, 2, queue);
    dispatch_source_set_event_handler(timer, ^{
        NSLog(@"11");
    });
    //因为创建的timer是未激活的 需要先激活才能操作
    dispatch_activate(timer);    
    long handle = dispatch_source_get_handle(timer);
    long mask = dispatch_source_get_mask(timer);
    NSLog(@"%ld %ld", handle, mask);
输出:
1 2
  • 返回调度源source的待处理数据
unsigned long dispatch_source_get_data(dispatch_source_t source);

该函数应在handler中调用。在handler之外调用此函数的结果是不确定的。
long 返回的结果根据dispatch_source_create传入的type而不同

 *  DISPATCH_SOURCE_TYPE_DATA_ADD:        应用定义的数据
 *  DISPATCH_SOURCE_TYPE_DATA_OR:         应用定义的数据
 *  DISPATCH_SOURCE_TYPE_DATA_REPLACE:    应用定义的数据
 *  DISPATCH_SOURCE_TYPE_MACH_SEND:       dispatch_source_mach_send_flags_t
 *  DISPATCH_SOURCE_TYPE_MACH_RECV:       dispatch_source_mach_recv_flags_t
 *  DISPATCH_SOURCE_TYPE_MEMORYPRESSURE   dispatch_source_memorypressure_flags_t
 *  DISPATCH_SOURCE_TYPE_PROC:            dispatch_source_proc_flags_t
 *  DISPATCH_SOURCE_TYPE_READ:            可读取的估计字节数
 *  DISPATCH_SOURCE_TYPE_SIGNAL:          自handler调用以来传递的信号数
 *  DISPATCH_SOURCE_TYPE_TIMER:           自handler调用以来计时器已触发的次数
 *  DISPATCH_SOURCE_TYPE_VNODE:           dispatch_source_vnode_flags_t
 *  DISPATCH_SOURCE_TYPE_WRITE:           估计可用缓冲区空间
  • 将数据合并到调度源source中,并将handler提交到目标队列queue再执行。
void dispatch_source_merge_data(dispatch_source_t source, unsigned long value);

该方法只支持dispatch_source_create的 type为DISPATCH_SOURCE_TYPE_DATA_ADDDISPATCH_SOURCE_TYPE_DATA_ORDISPATCH_SOURCE_TYPE_DATA_REPLACE的源
value 与待处理数据合并的值。传0时无效,也不会将handler提交到目标队列queue执行。

例:
    dispatch_queue_t queue = dispatch_queue_create("source", DISPATCH_QUEUE_SERIAL);
    dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, queue);
    dispatch_source_set_event_handler(source, ^{
        NSLog(@"source");
        long data = dispatch_source_get_data(source);
        NSLog(@"%ld", data);
    });
    dispatch_source_merge_data(source, 100);
    dispatch_source_merge_data(source, 200);
    dispatch_activate(source);
输出:
source
300
  • 设置计时器源的开始时间,间隔和回程值。
void dispatch_source_set_timer(dispatch_source_t source, dispatch_time_t start,
                uint64_t interval,uint64_t leeway);

该方法只支持dispatch_source_create的 type为DISPATCH_SOURCE_TYPE_TIMER的源
该方法会清除先前的计时器累积的所有未处理源数据。
如果定时器源已被取消,则调用此方法无效。
start 计时器下一次触发的时间
interval 每次触发的间隔 设为DISPATCH_TIME_FOREVER表示只会调用一次
leeway 系统可能会延迟计时器的启动时间,以提高功耗和系统性能。允许延迟的上限可以用leeway参数配置,下限则由系统控制。
如果指定的计时器源是使用DISPATCH_TIMER_STRICT的mask创建的,则系统将尽最大努力严格遵守所提供的leeway值,即使该值小于当前下限

例:
    dispatch_queue_t queue = dispatch_queue_create("source", DISPATCH_QUEUE_SERIAL);
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, DISPATCH_TIMER_STRICT, queue);
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 1 * NSEC_PER_SEC);
    dispatch_source_set_event_handler(timer, ^{
        (void)dispatch_source_get_data(timer);
        NSLog(@"timer");
    });
    dispatch_resume(timer);
输出:
timer
timer
...
  • 为调度源source设置激活后就调用的回调handler
void dispatch_source_set_registration_handler(dispatch_source_t source,
    dispatch_block_t _Nullable handler);

如果在dispatch_resumedispatch_activate之后调用该方法,那么handler将直接被提交到源的目标队列queue并执行
handler 提交到源的目标队列的回调

例:
    dispatch_queue_t queue = dispatch_queue_create("source", DISPATCH_QUEUE_SERIAL);
    dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, queue);
    dispatch_source_set_registration_handler(source, ^{
        NSLog(@"激活后回调");
    });
    dispatch_resume(source);
输出:
激活后回调
  • 为调度源source设置激活后就调用的函数handler
void dispatch_source_set_registration_handler_f(dispatch_source_t source,
    dispatch_function_t _Nullable handler);

handler 提交到源的目标队列的函数
函数handler要传递的参数通过dispatch_set_context设置

用法

用法1:
    dispatch_queue_t queue = dispatch_queue_create("source", DISPATCH_QUEUE_SERIAL);
    dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, queue);
    dispatch_source_set_event_handler(source,^{
        (void)dispatch_source_get_data(source);
        NSLog(@"操作一次");
    });
    dispatch_resume(source);
    //调用后会执行一次回调
    dispatch_source_merge_data(source, 1);
输出:
操作一次
用法2:
    dispatch_queue_t queue = dispatch_queue_create("source", DISPATCH_QUEUE_SERIAL);
    dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, queue);
    dispatch_source_set_event_handler(source,^{
        long data = dispatch_source_get_data(source);
        NSLog(@"操作一次 %ld", data);
    });
    dispatch_resume(source);
    dispatch_async(dispatch_get_main_queue(), ^{
        for (NSInteger i = 1; i < 5; i++) {
            dispatch_source_merge_data(source, i);
//            [NSThread sleepForTimeInterval:0.1];
        }
    });
输出: 虽然执行了4次dispatch_source_merge_data,但会将data相加后只执行一次回调handler
操作一次 10
若取消注释[NSThread sleepForTimeInterval:0.1]
输出:则会执行多次block
操作一次 1
操作一次 2
操作一次 3
操作一次 4
用法3:
    __block NSInteger timeout = 5;
    dispatch_queue_t queue = dispatch_queue_create("source", DISPATCH_QUEUE_SERIAL);
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, DISPATCH_TIMER_STRICT, queue);
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
    dispatch_source_set_event_handler(timer, ^{
        (void)dispatch_source_get_data(timer);
        if (timeout > 0) {
            NSLog(@"倒计时%ld秒", timeout);
            timeout--;
        } else {
            NSLog(@"倒计时结束");
            dispatch_source_cancel(timer);
        }
    });
    dispatch_activate(timer);
输出:
倒计时5秒
倒计时4秒
倒计时3秒
倒计时2秒
倒计时1秒
倒计时结束

你可能感兴趣的:(dispatch source.h)