美文网首页IOS学习揽收
GCD之dispatch_once 方法

GCD之dispatch_once 方法

作者: 指尖弹灰 | 来源:发表于2016-10-26 06:24 被阅读278次


dispatch_once(dispatch_once_t *predicate, dispatch_block_t block);

该函数的作用是保证block在程序的生命周期范围内只执行一次。

参数

predicate:该参数是为了表示该block是否执行过。 0表示未执行过  ,1表示执行过         block:该block就是只执行一次的任务。

通过下面的例1和例2,我们可以知道每次执行block前先对 onceToken 的值进行检查,0表示第一次执行,执行block后将onceToken 置为-1.如果onceToken 为-1,表示非第一执行,则不执行block.

例1:

// dispatch_once_t 必须是全局变量或static变量(保证dispatch_once_t只有一份实例)

static dispatch_once_t onceToken;

NSLog(@"AonceToken = %ld", onceToken);

dispatch_once(&onceToken, ^{

       NSLog(@"BonceToken = %ld", onceToken);

});

NSLog(@"ConceToken = %ld", onceToken);

运行结果:

2016-10-26 05:55:21.727 Test1[12244:878037] AonceToken = 0

2016-10-26 05:55:21.727 Test1[12244:878037] BonceToken = 140734777330000

2016-10-26 05:55:21.727 Test1[12244:878037] ConceToken = -1

例2:

static dispatch_once_t onceToken;

NSLog(@"AonceToken = %ld", onceToken);

dispatch_once(&onceToken, ^{

       NSLog(@"BonceToken = %ld", onceToken);

});

dispatch_once(&onceToken, ^{

     NSLog(@"DonceToken = %ld", onceToken);

});

NSLog(@"ConceToken = %ld", onceToken);

运行结果:

2016-10-26 05:59:54.945 Test1[12277:880650] AonceToken = 0

2016-10-26 05:59:54.945 Test1[12277:880650] BonceToken = 140734583380288

2016-10-26 05:59:54.945 Test1[12277:880650] ConceToken = -1

应用:如果想要某个行为在整个生命周期中只能被执行一次。最常用到的地方是例3 单例

例3: 单例

#import <Foundation/Foundation.h>

@interface TestObject : NSObject

+ (TestObject *)shareObject;

@end

@implementation TestObject

+ (TestObject *)shareObject {   

       static TestObject *share = nil;       

       static dispatch_once_t onceToken; 

       dispatch_once(&onceToken, ^{   

              NSLog(@"进入了哈哈哈");     

              if (!share) {         

                   share = [[TestObject alloc]init];       

              }

        });       

  return share;

}

@end

调用:

for (int i=0; i<2; i++) {

NSLog(@"第%d次--%@",i,[TestObject shareObject]);

}

结果:

2016-10-26 06:12:47.859 Test1[12436:886784] 进入了哈哈哈

2016-10-26 06:12:47.860 Test1[12436:886784] 第0次--<TestObject:0x7f8263d4b860>

2016-10-26 06:12:47.861 Test1[12436:886784] 第1次--<TestObject:0x7f8263d4b860>

可以发现多次“创建”对象的内存是一样的。也只有第一次创建时真正的创建。

原理:

dispatch_once(dispatch_once_t *predicate, dispatch_block_t block);

进入该方法,我们可以去看一下它的实现

void  _dispatch_once(dispatch_once_t *predicate, dispatch_block_t block)  {

          if (DISPATCH_EXPECT(*predicate, ~0l) != ~0l) {

                    dispatch_once(predicate, block);  //a

          }

}

如果predicate != -1  执行if里面的语句。因为没法看到a语句具体的实现,我们只能知道 a语句会执行block,同时将predicate = -1。但具体如何实现不知道。

理解1.1:#define DISPATCH_EXPECT(x, v) __builtin_expect((x), (v))

__builtin_expect是GCC(version>=2.9)引进的宏,其作用就是帮助编译器判断条件跳转的预期值,避免跳转造成时间浪费.__builtin_expect仅仅是告诉编译器优化,并没有改变其对真值的判断。

比如在内核代码中,经常会遇到  #define likely(x)  __builtin_expect(!!(x), 1)

__builtin_expect()告诉编译器,x可能是1的概率很大,编译器可以假设x是1的情况去对接下来的操作进行优化,以减少指令跳转带来的性能降低。但具体是不是1还要进行正式的判断,毕竟你x不一定是1.

理解1.2  ~0l

~0l 表示一个长整形(long)的0按位取反。  0l  写成16进制  0x00000000  ~0l  就是 0xFFFFFFFF  即-1

相关文章

  • GCD之dispatch_once 方法

    dispatch_once(dispatch_once_t *predicate, dispatch_block_...

  • Parser GCD 之总结篇

    Parser 之 GCD 总结篇 dispatch_once 在 process 周期内,只执行一次,保证唯一行...

  • GCD之dispatch_once

    前言 dispatch_once能保证任务只会被执行一次,即使同时多线程调用也是线程安全的。常用于创建单例、swi...

  • AFNetworking 中 GCD 的使用(6)

    该篇将是 AFNetworking 中 GCD 使用的总结篇。 dispatch_once 用来保证线程安全, 只...

  • GCD ④ dispatch_once

    dispatch_once (单例) dispatch_once 函数是保证在应用程序执行中只执行一次指定处理的 ...

  • GCD之dispatch_once源码剖析

    本文使用的源码是libdispatch-187.10版本。至于为啥是这个版本,因为这一版的实现相对来说比较直观、阅...

  • iOS 开发之 GCD 基础

    iOS 开发之 GCD 基础 本文主要为 GCD 的 队列和执行方法等基础总结,目录如下: [TOC] GCD是什...

  • GCD外传:dispatch_once

    dispatch_once的作用正如其名:对于某个任务执行一次,且只执行一次。 dispatch_once函数有两...

  • OC——52个有效方法:45.使用 dispatch_once

    代码示例 使用dispatch_once可以简化代码并且彻底保证线程安全。无需担心加锁或同步,所有问题GCD底层处...

  • 单例

    使用GCD快速创建dispatch_once 1, 单例在外界容易被篡改: 在.h中添加提示语 +(instanc...

网友评论

    本文标题:GCD之dispatch_once 方法

    本文链接:https://www.haomeiwen.com/subject/zedduttx.html