一、明确两点

1.Block可以访问Block函数以及语法作用域以内的外部变量。也就是说:一个函数里定义了一个block,这个block可以访问该函数的内部变量(当然还包括静态,全局变量),即block可以使用和本身定义范围相同的变量。

2.Block其实是特殊的Objective-C对象,可以使用copy、release等来管理内存,但和一般的NSObject的管理方式有些不同,稍后会说明。

二、Block语法

Block很像函数指针,这从Block的语法上就可以看出。

Block的原型:

返回值 (^名称)(参数列表)

Block的定义

^ 返回值类型 (参数列表) { 表达式 }

其中返回值类型和参数列表都可以省略,最简单的Block就是:

^{ ; };

一般的定义就是:

返回值 (^名称)(参数列表) = ^(参数列表){代码段};

为了方便通常使用typedef定义:

typedef void (^blk) (void);

三、Block存储域

Block能够截获自动变量,自动变量的当前值会被拷贝到栈上作为常量,此时不能在Block内对自动变量进行赋值操作,如果有这种需求,则需要该变量是:

1.静态变量

2.全局变量

3.或者使用__block修饰符

根据Block中是否引用了自动变量,可以将Block存储区域分类:

1.__NSStackBlock__存储在栈上

2.__NSGlobalBlock__存储在全局数据区域(和全局变量一样)

3.__NSMallocBlock__存储在堆上

没有引用自动变量或者在全局作用域的Block为__NSGlobalBlock__,其他的基本上都是__NSStackBlock__。对__NSStackBlock__执行copy操作会生成__NSMallocBlock__。

一般来说出问题的Block大部分都是__NSStackBlock__,超过了__NSStackBlock__的作用域__NSStackBlock__就会销毁。

四、对Block执行retain,copy方法的效果

Block是C语言的扩展,C语法也可以使用Block的语法,对应的C语言使用Block_copy、Block_release。

无论是__NSStackBlock__,还是__NSGlobalBlock__,执行retain都不起作用。而__NSMallocBlock__执行retain引用计数+1。

对于copy操作,__NSStackBlock__会被复制到堆上得到一份新的__NSMallocBlock__,__NSStackBlock__还是存在的,而__NSGlobalBlock__执行copy操作不起作用。而对__NSMallocBlock__执行copy操作会引起引用计数加1。

五、什么时候要对__NSStackBlock__执行copy操作?

配置在栈上的Block也就是__NSStackBlock__类型的Block,如果其所属的变量作用域结束该Block就会废弃。这个时候如果继续使用该Block,就应该使用copy方法,将__NSStackBlock__拷贝为__NSMallocBlock__。当__NSMallocBlock__的引用计数变为0,该__NSMallocBlock__就会被释放。

如果是非ARC环境,需要显式的执行copy或者antorelease方法。

而当ARC有效的时候,实际上大部分情况下编译器已经为我们做好了,自动的将Block从栈上复制到堆上。包括以下几个情况:

1.Block作为返回值时,类似在非ARC的时候,对返回值Block执行[[returnedBlock copy] autorelease];

2.方法的参数中传递Block时

3.Cocoa框架中方法名中还有useringBlock等时

4.GCD相关的一系列API传递Block时

比如:[mutableAarry addObject:stackBlock];这段代码在非ARC环境下肯定有问题,而在ARC环境下方法参数中传递__NSStackBlock__会自动执行copy,所以就不会出现问题。

六、Block的循环引用

对于非ARC下,为了防止循环引用,我们使用__block来修饰在Block中使用的对象。

对于ARC下,为了防止循环引用,我们使用__weak来修饰在Block中使用的对象。

原理就是:ARC中,Block中如果引用了__strong修饰符的自动变量,则相当于Block对该对象的引用计数+1。

七、代码验证

验证__NSStackBlock__

我们往可变数组中添加一个__NSStackBlock__。

在MRC环境下,__NSStackBlock__在自身作用域结束后就从栈中释放,所以我们再次使用它的时候,程序就会发生崩溃。

在ARC环境下,编译器会自动对__NSStackBlock__执行copy,拷贝一份到堆上生成一个新的__NSMallocBlock__,我们再次使用它的时候,程序正常运行。

#import

void addBlockToArray(NSMutableArray *arrayM) {

int a = 1;

[arrayM addObject:^{

printf("%d\n",a);

}];

}

int main(int argc, const char * argv[]) {

@autoreleasepool {

NSMutableArray *arrayM = [NSMutableArray array];

addBlockToArray(arrayM);

void (^block)() = [arrayM objectAtIndex:0];

block();

NSLog(@"%@",block);

}

return 0;

}

验证__NSGlobalBlock__

我们往可变数组中添加一个__NSGlobalBlock__。

不管是在MRC还是ARC环境下,__NSGlobalBlock_都是存储在程序的数据区,所以程序在MRC或ARC环境下都能正常执行。

#import

void addBlockToArray(NSMutableArray *arrayM) {

[arrayM addObject:^{

printf("global\n");

}];

}

int main(int argc, const char * argv[]) {

@autoreleasepool {

NSMutableArray *arrayM = [NSMutableArray array];

addBlockToArray(arrayM);

void (^block)() = [arrayM objectAtIndex:0];

block();

NSLog(@"%@",block);

}

return 0;

}

block引用c语言数组,Block在ARC和MRC下的使用分析相关推荐

  1. [iOS]ARC和MRC下混编

    1.在MRC工程中使用ARC的文件(例如AFNetworking,SDWebImage,MJRefresh等)在Build Phases里找到对应.m 在后面添加-fobjc-arc(代表这个文件使用 ...

  2. c语言指针引用数组元素,c语言——数组指针和通过指针引用数组元素的方法总结...

    1.数组指针:即指向数组的指针 那么, 如何声明一个数组指针呢? int (* p)[10]; /*括号是必须写的,不然就是指针数组:10是数组的大小*/ 1 拓展:有指针类型元素的数组称为指针数组. ...

  3. C语言指针基础知识点(六)--通过指针引用多维数组

    指针系列目录   C语言指针基础知识点(一)–指针及指针变量   C语言指针基础知识点(二)–指针变量的引用   C语言指针基础知识点(三)–指针变量作为函数参数   C语言指针基础知识点(四)–通过 ...

  4. C语言-数组的定义和引用

    数组的定义和引用 1. 一维数组.二维数组的定义.初始化和引用方法 数组数据的特点: 数组: 一般形式:类型说明符 数组名[常量表达式]: 说明: 一维数组的引用 1. 引用方式: 二维数组 二维数组 ...

  5. C语言定义和引用二维数组

    怎样定义和引用二维数组 二维数组常称为矩阵.把二维数组写成行(row)和列(column)的排列形式,可以有助于形象地理解二维数组的逻辑结构. 一.怎样定义二维数组 其基本概念与方法与一维数组相似,如 ...

  6. 彻底弄懂C语言数组名

    先定义一个一维数组 int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 一.数组名是什么 数组名的值是数组首元素的指针常量. 数组名不是指针,但大多数使用到数组名的 ...

  7. python调用golang 数组_Go 语言数组复制

    Go 语言数组复制 Golang编程语言中的数组与其他编程语言非常相似.在程序中,有时我们需要存储一组相同类型的数据,例如学生评分列表.这种类型的集合使用数组存储在程序中.数组是固定长度的序列,用于将 ...

  8. c语言数组与指针浅析

    大部分人,特别是初学者对于一些奇怪的数组表达式表示诧异. 举个例子: #include<stdio.h> int main(void) { int a[3]; for(int i = 0; ...

  9. c语言数组数据用指针查找,c语言数组与指针_指针篇_2011.ppt

    c语言数组与指针_指针篇_2011 指 针 6.2 指针的概念6.3 指针与数组6.4 字符串的指针6.5 指针数组和指向指针的指针;6.2.1 地址与指针的概念 ;指针的概念;内存地址;2.数组与地 ...

最新文章

  1. rman备份后为什么要同时备份归档日志
  2. 删库跑路大神「后悔」了?我只不过犯了大家都会犯的编程错误!
  3. torch.nn.LogSoftmax()与输入具有相同尺寸和形状的张量,其值在[-inf,0)范围内
  4. Visual Studio Code常用快捷键
  5. 全球及中国斜交胎市场品牌竞争形势与投资策略分析报告2022年
  6. vim括号操作(转)
  7. redhat php5 安装,完整的linux(RedHat)+php5.3.10+mysql5.5.19+apache2.2.22安装配置说明
  8. Android知识点 - 收藏集 - 掘金
  9. linux编译安装mysql5.1.x
  10. MyBatis 分页插件 PageHelper
  11. Android系统架构图
  12. 可用性目标概念化(摩西十戒)
  13. ssm启动不报错_搭建ssm+maven环境,启动报错,说spring监听无法实例化,求解?
  14. Java定时器cron表达式
  15. 大数据工程应用 数据分析_大数据工程的方式
  16. 理论+实验:LAMP网站服务器部署(超详细版本)
  17. thinningopencv
  18. 禾匠二开系列之兑换码禁用以后启用功能
  19. 电源学习(1):stm32单片机buck电路可调电源设计介绍
  20. 千万千万不可运行的 Linux 命令

热门文章

  1. 滤波器设计(二)模拟到数字
  2. 10.28T5 tarjan+dfs
  3. VMware Pro 14.1.2 官方正式版及激活密钥
  4. 英特尔云计算策略以Nehalem为主
  5. Spring Boot - 开发Web应用
  6. java web获取请求体内容
  7. 2015第16周四自控力
  8. javascript中正则表达式和ruby中的一点差异
  9. 思考、学习新技术的原则和方式
  10. 【JS】引用类型之String