1. block的层级
Block就是一个里面存储了指向函数体中包含定义block时的代码块的函数指针,以及block外部上下文变量等信息的结构体。 它是一个object对象,可以通过可以通过object_getClass 来获取对象的class。
通过以下方法,就能获得block的层级
- (void)logBlockIsObject {
int i = 10;
void (^tmpBlock)(void) = ^{
NSLog(@"i = %d", i);
};
Class blockClass = object_getClass(tmpBlock);
while (blockClass) {
NSLog(@"class = %@", blockClass);
blockClass = class_getSuperclass(blockClass);
}
}
打印出tmpBlock的类的层级:NSMallocBlock 、__NSMallocBlock 、NSBlock、NSObject
2. block内存分析
block的内存分布:block有三种种类:globalBlock(全局)、mallocBlock(堆区)、stackBlock(栈区)
1、没有外部变量的block:统统都属于globalBlock
2、有外部变量的情况:
- 2.1 全局变量、全局静态变量、局部静态变量(统统都是globalBlock);
- 2.2 普通的外部变量: strong和copy修饰的是一样的,为mallocBlock(在堆区);weak修饰的,为stackBlock,在栈区
3、如果block作为自定义函数参数,block在栈区;系统的函数,会把block转移到mallocblock,也就是堆区
注意1:当block为globalBlock时,哪怕是用weak修饰的block,依然能够调用成功。如下:
- (void)blockMemory {
static int tempPartValue = 10;
_strongBlock = ^{
NSLog(@"_strongBlock - %d", globalValue);
};
_copyBlock = ^{
NSLog(@"_copyBlock - %d", globalValue);
};
_weakBlock = ^{
// NSLog(@"_weakBlock - %d", globalValue);
NSLog(@"_weakBlock");
};
NSLog(@"_strongBlock : %@,_copyBlock : %@,_weakBlock : %@", object_getClass(_strongBlock), object_getClass(_copyBlock), object_getClass(_weakBlock));
_strongBlock1 = ^(int i) {
NSLog(@"_strongBlock1 : i=%d", i);
};
_copyBlock1 = ^(int i) {
NSLog(@"_copyBlock1 : i=%d", i);
};
_weakBlock1 = ^(int i) {
NSLog(@"_weakBlock1 : i=%d", i);
};
NSLog(@"strongBlock1 %@, copyBlock1 %@, weakBlock1 %@", object_getClass(_strongBlock1), object_getClass(_copyBlock1), object_getClass(_weakBlock1));
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
_weakBlock();
}
在touchesBegan方法中调用_weakBlock,依然能够打印成功。
注意2:当block在栈区的时候,也就是为stackBlock的时候,再调用block会报错,因为已经被释放了。
注意3:你自定义的函数,block作为参数,block会是在栈区;但是如果你调用了系统的方法,block它会自动copy,变成mallocblock。如下:
object_getClass 类似这样的方法,只要不是自己写的,都是系统的方法。
注意4:作为返回值的block,情况和上面一样
- 当没有外部变量或者有全局变量、全局静态变量、局部静态变量(统统都是globalBlock)。
-
当有普通外部变量的时候,是 mallocblock。
如下: