1.Block简介:
可以简单的理解,Block其实包含两个部分内容:
1)Block执行的代码,这是在编译的时候已经生成好的;
2)一个包含Block执行时需要的所有外部变量值的数据结构。 Block将使用到的、作用域附近到的变量的值建立一份快照拷贝到栈
P.S. Block与函数的区别:
Block可以访问函数以外、词法作用域以内的外部变量的值。换句话说,Block不仅 实现函数的功能,还能携带函数的执行环境
2.Block的基本用法:
// 声明一个Block变量
long (^sum) (int, int) = nil;// sum是个Block变量,该Block类型有两个int型参数,返回类型是long。
// 定义Block并赋给变量
sumsum = ^ long (int a, int b) { return a + b;};
// 调用Block:
long s = sum(1, 2);
为了看着比较顺眼,通常使用typedef进行定义
typedef long (^block)(int, int);
- (block) sumBlock {
int base = 100;
block blk = ^ long (int a, int b) {
return base + a + b;
}
return [[blk copy] autorelease];}
Block在内存中的位置
根据Block在内存中的位置分为三种类型NSGlobalBlock,NSStackBlock, NSMallocBlock。
NSGlobalBlock:类似函数,位于text段;
NSStackBlock:位于栈内存,函数返回后Block将无效;
NSMallocBlock:位于堆内存。
block blk1 = ^ long (int a, int b) { return a + b;};
NSLog(@"blk1 = %@", blk1);// blk1 = <__NSGlobalBlock__: 0x47d0>
int base = 100;
block blk2 = ^ long (int a, int b) { return base + a + b;};
NSLog(@"blk2 = %@", blk2); // blk2 = <__NSStackBlock__: 0xbfffddf8>BlkSum
blk3 = [[blk2 copy] autorelease];
NSLog(@"blk3 = %@", blk3); // blk3 = <__NSMallocBlock__: 0x902fda0>
blk1与blk2的区别在于:
blk1没有使用block外的任何外部变量,Block不需要建立局部变量值的快照,这就使得blk1与函数没有任何的区别
blk2使用了外部的变量base,在定义(注意是定义,不是运行)blk2时,局部变量base当前值被copy到栈上,作为常量供Block使用
例:
int base = 100;
base += 100;
block sum = ^ long (int a, int b) {
return base + a + b;
};
base++;
printf("%ld",sum(1,2));
打印结果为:203
在Block内变量base是只读的,如果想在Block内改变base的值,在定义base时要用:__block int base = 100;
__block int base = 100;
base += 100;
BlkSum sum = ^ long (int a, int b) {
base += 10;
return base + a + b;
};
base++;
printf("%ld\n",sum(1,2));
printf("%d\n",base);
打印结果为:214和211
Block中使用__block修饰的变量时,将取变量此刻运行时的值,而不是定义时的快照
Block的copy、retain、release操作
不同于NSObjec的copy、retain、release操作:
Block_copy与copy等效,Block_release与release等效;
对Block不管是retain、copy、release都不会改变引用计数retainCount,retainCount始终是1;
1)NSGlobalBlock:retain、copy、release操作都无效;
2)NSStackBlock:retain、release操作无效,必须注意的是,NSStackBlock在函数返回后,Block内存将被回收。即使retain也没用。容易犯的错误是[[mutableAarry addObject:stackBlock],在函数出栈后,从mutableAarry中取到的stackBlock已经被回收,变成了野指针。正确的做法是先将stackBlock copy到堆上,然后加入数组:[mutableAarry addObject:[[stackBlock copy] autorelease]]。支持copy,copy之后生成新的NSMallocBlock类型对象。
3)NSMallocBlock支持retain、release,虽然retainCount始终是1,但内存管理器中仍然会增加、减少计数。copy之后不会生成新的对象,只是增加了一次引用,类似retain;
P.S尽量不要对Block使用retain操作。
Block对不同类型的变量的存取
基本类型
局部自动变量,在Block中只读。Block定义时copy变量的值,在Block中作为常量使用,所以即使变量的值在Block外改变,也不影响他在Block中的值。
static变量、全局变量。如果把上个例子的base改成全局的、或static。Block就可以对他进行读写了。因为全局变量或静态变量在内存中的地址是固定的,Block在读取该变量值的时候是直接从其所在内存读出,获取到的是最新值,而不是在定义时copy的常量。
Block变量,被__block修饰的变量称作Block变量。 基本类型的Block变量等效于全局变量、或静态变量。
Block被另一个Block使用时,另一个Block被copy到堆上时,被使用的Block也会被copy。但作为参数的Block是不会发生copy的
本文具体参考:http://blog.csdn.net/wildfireli/article/details/21979955
网友评论