Dispatch(semaphore+block+time)

Dispatch.h Semaphore.h //GCD信号资源量

dispatch_semaphore_t是GCD中用来控制资源访问量的。共有三个函数
dispatch_semaphore_tdispatch_semaphore_create(long value); //创建同时可用资源量。 longdispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout); //设置可用资源超时时间 longdispatch_semaphore_signal(dispatch_semaphore_t dsema); //解除对信号资源量的限制

  • 对dispatch_semaphore_t的理解可以是:*
  1. 利用dispatch_semaphore_create创建系统可以同时使用的资源数,意思也就是临时对系统可用资源数添加一个限制。
  2. dispatch_semaphore_wait用这个函数设置一下对可用资源增加这个限制的时间。一般两个值DISPATCH_TIME_NOWDISPATCH_TIME_FOREVER,也可以理解为临时降低系统可用资源的数量。
  3. dispatch_semaphore_signal发送一个信号解除对系统可用资源数量的限制。
总结一下:这三个函数有点像高速公路临时收费站,第一个函数增加一个收费站,也就是增加几个收费窗口,第二个函数也就是这个临时收费站有多久有效期,第三个函数相当于收费站上级给收费站发送的撤销通知。
代码
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1); //数字可以修改 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); //时间可以修改你的需要被限制代码dispatch_semaphore_signal(semaphore);

Dispatch_time 两个函数
dispatch_time_t dispatch_time(dispatch_time_t when, int64_t delta); dispatch_time_t dispatch_walltime(const struct timespec *_Nullable when, int64_t delta);

第一个函数 第一个参数是从什么时间开始,一般直接传 DISPATCH_TIME_NOW; 表示从现在开始
第二个参数表示具体的时间长度(不能直接传 int 或 float), 可以写成这种形式 (int64_t)3* NSEC_PER_SEC
#define NSEC_PER_SEC 1000000000ull每秒有1000000000纳秒 #define NSEC_PER_MSEC 1000000ull每毫秒有1000000纳秒 #define USEC_PER_SEC 1000000ull每秒有1000000微秒 #define NSEC_PER_USEC 1000ull每微秒有1000纳秒

注意 delta 的单位是纳秒!
1秒的写作方式可以是 1* NSEC_PER_SEC; 1000* NSEC_PER_MSEC; USEC_PER_SEC* NSEC_PER_USEC

第二个函数 第一个参数是一个结构体, 创建的是一个绝对的时间点,比如 2016年10月10日8点30分30秒, 如果你不需要自某一个特定的时刻开始,可以传 NUll,表示自动获取当前时区的当前时间作为开始时刻, 第二参数意义同第一个函数
dispatch_time_t time = dispatch_walltime(NULL, 5* NSEC_PER_SEC);
两个函数的不同
例如: 从现在开始,1小时之后是触发某个事件
使用第一个函数创建的是一个相对的时间,第一个参数开始时间参考的是当前系统的时钟,当 device 进入休眠之后,系统的时钟也会进入休眠状态, 第一个函数同样被挂起; 假如 device 在第一个函数开始执行后10分钟进入了休眠状态,那么这个函数同时也会停止执行,当你再次唤醒 device 之后,该函数同时被唤醒,但是事件的触发就变成了从唤醒 device 的时刻开始,1小时之后
而第二个函数则不同,他创建的是一个绝对的时间点,一旦创建就表示从这个时间点开始,1小时之后触发事件,假如 device 休眠了10分钟,当再次唤醒 device 的时候,计算时间间隔的时间起点还是 开始时就设置的那个时间点, 而不会受到 device 是否进入休眠影响
源引自CSDN博客顽儿去
Dispatch_block
QOS_CLASS_T 质量服务等级,简单点就是优先级
  1. DISPATCH_BLOCK_BARRIER //提交并发队列时作为一个栅栏代码块使用,直接调用代码块的时候,这个参数没有任何作用
  2. DISPATCH_BLOCK_DETACHED 如果直接调用用这个flag创建的代码块,block代码块执行过程中将忽略调用线程之前给代码块添加的一些属性。本代码块执行过程中和质量服务等级无关,和属性无关和请求无关,如果这个代码块被提交到一个队列,那么它的执行和队列属性有关。
  3. DISPATCH_BLOCK_ASSIGN_CURRENT 用这个flag创建的代码块将被获得创建代码块时的上下文属性,如果直接使用这个block,那么它创建时获得的上下文属性等将在调用它的线程中可以使用,如果在一个队列中调用这个block,那么将会用提交时的上下文属性替换创建时的上下文属性。使用DISPATCH_BLOCK_NO_QOS_CLASSdispatch_block_create_with_qos_class()方法指定的质量服务等级会优先级高于用这个flag指定的质量服务优先级
  4. DISPATCH_BLOCK_NO_QOS_CLASS 不指定质量服务优先级创建的block,直接使用这个block,这个block的质量服务优先级是由调用线程决定的,如果被提交到一个队列,将用提交时的质量服务级别替换相关的block实例的默认行为。创建的block用在函数dispatch_block_create_with_qos_class()中,这个flag将被忽略。
  5. DISPATCH_BLOCK_INHERIT_QOS_CLASS 队列的质量服务优先级优先于block中用这个flag指定的优先级,本参数只有在队列没有指定质量服务优先级的时候才起作用,dispatch_block 提交到一个异步执行队列的时候使用默认是使用这个flag的(如果不是用dispatch_block创建的block),如果队列中指定DISPATCH_BLOCK_ENFORCE_QOS_CLASS或者直接调用block,这个参数将不起作用。
  6. DISPATCH_BLOCK_ENFORCE_QOS_CLASS block的质量服务优先级大于队列指定的质量服务优先级,队列中同步执行的block使用这个flag作为默认值,直接调用也是使用这个作为默认值。
dispatch_block_t dispatch_block_create(dispatch_block_flags_t flags, dispatch_block_t block);

  1. 第一种创建block方式
    用指定的flag值和block在堆区(copy的方式)创建一个新的block,新的block可以通过dispatch_async()调用或者直接调用,可以被调用任意次数,但是只有第一次能被dispatch_block_wait()等待和dispatch_block_notify()观察
    如果新创建的block被提交到一个队列,除非block是用DISPATCH_BLOCK_ASSIGN_CURRENT,DISPATCH_BLOCK_NO_QOS_CLASS,DISPATCH_BLOCK_DETACHED创建的,否则它的质量服务优先级都由创建这个block时指定的flag决定。
    新创建的block执行时的质量服务优先级同时取决于队列的QOS 和 创建block时的flag,
dispatch_block_texcutBlock = dispatch_block_create(DISPATCH_BLOCK_BARRIER, ^{ NSLog(@"perform blockwithonly one"); });

  1. 第二种创建block方式
直接调用的时候只要只要创建的时候的QOS不会导致调用线程的QOS变低就行。
如果新创建的block被提交到一个串行队列并且被指定了QOS,系统将尽可能的用必要的qos覆盖来确保这个提交到串行队列的block在同等级的qos或者更高的qos等级执行。
qos传QOS_CLASS_UNSPECIFIED和指定block的flag为DISPATCH_BLOCK_NO_QOS_CLASS效果一样,传其他值将导致返回的block为空。
relative_priority 是一个负的便宜量,如果指定一个大于0 小于QOS_MIN_RELATIVE_PRIORITY(一个宏定义值为-15)的值将导致创建出来的block为null
block 用来创建新block的原始block
dispatch_block_ttestBlock =dispatch_block_create_with_qos_class(DISPATCH_BLOCK_NO_QOS_CLASS, QOS_CLASS_UNSPECIFIED, -10, ^{ NSLog(@"这是dispatch_block_create_with_qos_class创建的block"); }); testBlock(); //直接调用

同步阻塞线程,直到传入的block执行完成或者时间过期(也就是传入的时间参数过期了)
dispatch_block_wait(testBlock, DISPATCH_TIME_FOREVER);

给被执行的block添加一个通知block,当被执行的block执行完成之后会自动调用通知block
dispatch_block_notify(testBlock, dispatch_get_main_queue(), ^{ NSLog(@"notificationBlock"); });

【Dispatch(semaphore+block+time)】只能取消还没有执行的block,已经在执行的block不能被取消
dispatch_block_cancel(testBlock);

    推荐阅读