block引用c语言数组,Block在ARC和MRC下的使用分析
一、明确两点
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下的使用分析相关推荐
- [iOS]ARC和MRC下混编
1.在MRC工程中使用ARC的文件(例如AFNetworking,SDWebImage,MJRefresh等)在Build Phases里找到对应.m 在后面添加-fobjc-arc(代表这个文件使用 ...
- c语言指针引用数组元素,c语言——数组指针和通过指针引用数组元素的方法总结...
1.数组指针:即指向数组的指针 那么, 如何声明一个数组指针呢? int (* p)[10]; /*括号是必须写的,不然就是指针数组:10是数组的大小*/ 1 拓展:有指针类型元素的数组称为指针数组. ...
- C语言指针基础知识点(六)--通过指针引用多维数组
指针系列目录 C语言指针基础知识点(一)–指针及指针变量 C语言指针基础知识点(二)–指针变量的引用 C语言指针基础知识点(三)–指针变量作为函数参数 C语言指针基础知识点(四)–通过 ...
- C语言-数组的定义和引用
数组的定义和引用 1. 一维数组.二维数组的定义.初始化和引用方法 数组数据的特点: 数组: 一般形式:类型说明符 数组名[常量表达式]: 说明: 一维数组的引用 1. 引用方式: 二维数组 二维数组 ...
- C语言定义和引用二维数组
怎样定义和引用二维数组 二维数组常称为矩阵.把二维数组写成行(row)和列(column)的排列形式,可以有助于形象地理解二维数组的逻辑结构. 一.怎样定义二维数组 其基本概念与方法与一维数组相似,如 ...
- 彻底弄懂C语言数组名
先定义一个一维数组 int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 一.数组名是什么 数组名的值是数组首元素的指针常量. 数组名不是指针,但大多数使用到数组名的 ...
- python调用golang 数组_Go 语言数组复制
Go 语言数组复制 Golang编程语言中的数组与其他编程语言非常相似.在程序中,有时我们需要存储一组相同类型的数据,例如学生评分列表.这种类型的集合使用数组存储在程序中.数组是固定长度的序列,用于将 ...
- c语言数组与指针浅析
大部分人,特别是初学者对于一些奇怪的数组表达式表示诧异. 举个例子: #include<stdio.h> int main(void) { int a[3]; for(int i = 0; ...
- c语言数组数据用指针查找,c语言数组与指针_指针篇_2011.ppt
c语言数组与指针_指针篇_2011 指 针 6.2 指针的概念6.3 指针与数组6.4 字符串的指针6.5 指针数组和指向指针的指针;6.2.1 地址与指针的概念 ;指针的概念;内存地址;2.数组与地 ...
最新文章
- rman备份后为什么要同时备份归档日志
- 删库跑路大神「后悔」了?我只不过犯了大家都会犯的编程错误!
- torch.nn.LogSoftmax()与输入具有相同尺寸和形状的张量,其值在[-inf,0)范围内
- Visual Studio Code常用快捷键
- 全球及中国斜交胎市场品牌竞争形势与投资策略分析报告2022年
- vim括号操作(转)
- redhat php5 安装,完整的linux(RedHat)+php5.3.10+mysql5.5.19+apache2.2.22安装配置说明
- Android知识点 - 收藏集 - 掘金
- linux编译安装mysql5.1.x
- MyBatis 分页插件 PageHelper
- Android系统架构图
- 可用性目标概念化(摩西十戒)
- ssm启动不报错_搭建ssm+maven环境,启动报错,说spring监听无法实例化,求解?
- Java定时器cron表达式
- 大数据工程应用 数据分析_大数据工程的方式
- 理论+实验:LAMP网站服务器部署(超详细版本)
- thinningopencv
- 禾匠二开系列之兑换码禁用以后启用功能
- 电源学习(1):stm32单片机buck电路可调电源设计介绍
- 千万千万不可运行的 Linux 命令