一、block放在哪里

我们针对不同情况来讨论block的存放位置:

1.栈和堆

以下情况中的block位于堆中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void foo()
{
    __block int i = 1024;
    int j = 1;
    void (^blk)(void);
    void (^blkInHeap)(void);
    blk = ^{ printf("%d, %d\n", i, j);};//blk在栈里
    blkInHeap = Block_copy(blk);//blkInHeap在堆里
}
 
- (void)fooBar
{
    _oi = 1;
    OBJ1* oj = self;
    void (^oblk)(void) = ^{ printf("%d\n", oj.oi);};
    void (^oblkInHeap)(void) = [oblk copy];//oblkInHeap在堆中
}

2.全局区

以下情况中的block位于全局区:

1
2
3
4
5
6
7
8
9
10
static int(^maxIntBlock)(int, int) = ^(int a, int b){return a>b?a:b;};
- (void)fooBar
{
     int(^maxIntBlockCopied)(int, int) =[maxIntBlock copy];
}
 
void foo()
{
     int(^maxIntBlockCopied)(int, int) = Block_copy(maxIntBlock);
}

需要注意的是,这里复制过后的block依旧位于全局区,实际上,复制操作是直接返回了原block对象。

二、block引用的变量在哪里

1.全局区

全局区的变量存储位置与block无关:

1
2
3
4
5
6
7
8
static int gVar = 0;
//__block static int gMVar = 1;
 
void foo()
{
    static int stackVar = 0;
//    __block static int stackMVar = 0;
}

注意,static变量是不允许添加__block标记的

2.堆栈

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void foo()
{
    __block int i = 1024;//此时i在栈上
    int j = 1;//此时j在栈上
    void (^blk)(void);
    blk = ^{printf("%d, %d\n", i, j); };//此时,blk已经初始化,它会拷贝没有__block标记的常规变量自己所持有的一块内存区,这块内存区现在位于栈上,而对于具有__block标记的变量,其地址会被拷贝置前述的内存区中
    blk();//1024, 1
    void(^blkInHeap)(void) = Block_copy(blk);//复制block后,block所持有的内存区会被拷贝至堆上,此时,我们可以说,这个block现在位于堆上
    blkInHeap();//1024,1
    i++;
    j++;
    blk();//1025,1
    blkInHeap();//1025,1
}

让我们一步步剖析:

首先,我们在栈上创建了变量ij,并赋予初始值,然后创建一个block变量名为blk,但未赋值。

然后我们初始化这个blk,赋值为一个只有一句printf的block,值得注意的是,一个block一旦创建,其引用到的常规变量会进行如下操作:

没有__block标记的变量,其值会被复制一份到block私有内存区

有__block标记的变量,其地址会被记录在block私有内存区

然后调用blk,打印1024, 1很好理解

接下来复制blk到堆,名曰blkInHeap,调用之,打印1024, 1也很好理解

接下来我们为ij增值,使其变为1025和2,此时再调用blk或者blkInHeap,会发现结果为1025, 1,这是因为变量j早已在创建原始的block时,被赋值进block的私有内存区,后续对i的操作并非操作的私有内存区的复制品,当调用blk或者blkInHeap时,其打印使用的是私有内存区的复制品,故而打印结果依旧为1;而变量j的修改会实时生效,因为block记录的是它的地址,通过地址来访问其值,使得外部对j的修改在block中得以生效。对于变量i来讲,可算是物是人非吧?

因此,无论j++这一句放到blk()这句之前或者之后,只要它位于block初始化之后,这段代码执行的控制台打印结果都会是:1024, 1。而不是1024, 2(假设不调用i++)

最新文章

  1. C#实现通过模板自动创建Word文档的方法
  2. 【C#学习笔记】浏览目录得到路径
  3. jQuery响应式幻灯片插件jquery.glide.js(支持触摸&轻量级)
  4. java的一些程序
  5. 国内首款开源的互联网支付系统roncoo-pay
  6. Netty4 学习笔记之一:客户端与服务端通信 demo
  7. Stars(二维树状数组)
  8. Java8新特性第3章(Stream API)
  9. Unity Input,生命周期,Light,获取组件
  10. C++内存读写例子
  11. 【vue】vue +element 搭建项目,实现实时输入效果时停止输入后发送请求
  12. C-Lodop打印服务没启动怎么办
  13. PHP工厂方法模式
  14. C# 我的小画板
  15. Andriod Studio两种签名机制V1和V2的区别
  16. request请求 HTTPBody 格式
  17. 关于微信小程序如何解决多层循环嵌套
  18. 2019.02.06 bzoj4503: 两个串(fft)
  19. Prime Gift CodeForces - 912E (中途相遇)
  20. linux abstract model of virtual memory

热门文章

  1. pod应用--备用
  2. 超强Altium Designer焊盘为梅花状连接,过孔为直接连接的方法
  3. (3)tomcat源代码分析环境的搭建
  4. TCP/IP 中文译名为传输控制协议/因特网互联协议,又叫网络通讯协议
  5. 全球扫货指南:面向中国消费者的全球奢侈品旅游导购服务 |PingWest中文网
  6. linux内核--中断和中断处理(一)
  7. Annotation(三)——Spring注解开发
  8. poj 1466 Girls and Boys(二分匹配之最大独立集)
  9. IOS uitableviewcell 向左滑动删除编辑等
  10. 深度剖析JDK动态代理机制