- block是一个对象,调用block的父类最终都继承自NSObject.
// __NSGlobalBlock__ : __NSGlobalBlock : NSBlock : NSObject
void (^block)(void) = ^{
NSLog(@"Hello");
};
NSLog(@"%@", [block class]);
NSLog(@"%@", [[block class] superclass]);
NSLog(@"%@", [[[block class] superclass] superclass]);
NSLog(@"%@", [[[[block class] superclass] superclass] superclass]);
- block有三种类型,可以通过调用class方法或者isa指针查看具体类型,定义三个block:
void (^block1)(void) = ^{
NSLog(@"Hello");
};
int age = 10;
void (^block2)(void) = ^{
NSLog(@"Hello - %d", age);
};
NSLog(@"%@ %@ %@", [block1 class], [block2 class], [^{
NSLog(@"%d", age);
} class]);
打印结果:__NSGlobalBlock__ __NSMallocBlock__ __NSStackBlock__对应的就是block的三种类型。并且三种类型分别在内存的不同位置,如图:
内存是从上到下增长的
- .text区域是代码段,平时定义的所有的类都在这个区域。
- .data全局变量之类的包括static定义的局部变量。__NSGlobalBlock__类型的block就在这个区域,不常用。
- 堆段是需要程序员自己申请管理内存,也就是alloc、free之类的。__NSMallocBlock__类型再这个区域
- 栈段一般放的局部变量,特点是自动释放内存,如果局部变量所在的作用域结束了,就自动销毁了。__NSStackBlock__在栈这个区域
那么block类型是怎么判断的呢?
1、__NSGlobalBlock__类型的block是没有访问auto变量。
2、__NSStackBlock__类型的block一般类型是访问了auto变量(mrc情况下,因为arc已经自动管理了内存),这种类型的block是在栈段,如果block所在的函数调用完,这个block就会销毁,当其他地方调用这种类型的block时候访问就会有问题。
3、__NSMallocBlock__类型的block是拿到__NSStackBlock__进行拷贝之后返回之后就是这种类型的block。总结如下:
那么__NSGlobalBlock__跟__NSMallocBlock__拷贝之后呢?
如果__NSGlobalBlock__拷贝之后还是__NSGlobalBlock__类型的。而__NSMallocBlock__类型的block拷贝之后引用计数器增加,类型不会改变。总结如图:
以上是mrc情况下,但在实际开放情况下用的都是arc,在arc情况下, 编译器会根据情况自动将栈上的block复制到堆上,比如:
a、block作为返回值的时候。
b、将block赋值给__strong指针时。
c、block作为Cocoa API中方法名含有usingBlock的方法参数时。
d、block作为GCD API参数时。

863

被折叠的 条评论
为什么被折叠?



