主要讲解 Block 的分类和变量捕获的强弱引用;
Block部分一
Block部分二
Block部分三
Block知识点总结
以下内容的测试主要针对ARC
环境; MRC
下直接贴出测试结果, 不再贴出测试代码, 具体请自行测试MRC
环境;
1. 首先是Block的分类
- NSStackBlock : 访问了
auto
变量 == 存放在栈区 - NSMallocBlock : 对
__NSStackBlock__
进行copy
操作 == 存放在堆区 - NSGlobalBlock : 没有访问
auto
变量 == 存放在数据区域
他么的继承关系如图;
总结:
没有访问
auto
变量,其class
是__NSGlobalBlock__
;
MRC下访问了auto
变量, 其class
就是__NSStackBlock__
然后copy
这个block
;,其class
变为__NSMallocBlock__
; 没有访问auto
变量,其class
是__NSGlobalBlock__
;
ARC下访问了auto
变量, 其class
结果是__NSMallocBlock__
, 因为系统自动帮忙进行了类似copy
的操作将其赋值到堆区;
2. ARC下什么时候会对NSStackBlock进行copy操作?
- 访问
auto
变量时; - 系统方法中有
UsingBlock
的block
时; - 使用
GCD
的block
时;
- (void)viewDidLoad {
[super viewDidLoad];
///最简单的block, 没有访问auto变量, 始终都是__NSGlobalBlock__
NSLog(@"type: %@", [^{} class]);
///访问auto局部变量的block; MRC是__NSStackBlock; ARC下系统copy操作到堆区, 所以就是__NSMallocBlock;
int a = 10;
void(^block1)(void) = ^{
NSLog(@"%d", a);
};
NSLog(@"type: %@", [block1 class] );
///返回值block中没有访问auto局部变量; 始终都是__NSGlobalBlock__
ReturnBlock block2 = [self getblock1];
NSLog(@"block作为返回值时, type%@ ", [block2 class]);
///返回值block中有访问auto局部变量;MRC是__NSStackBlock; ARC下系统copy操作到堆区, 所以就是__NSMallocBlock;
ReturnBlock block3 = [self getblock2];
NSLog(@"block作为返回值时, type%@ ", [block3 class]);
///block被强指针指向, 有访问auto变量, ARC下会默认copy到堆区
int b = 10;
ReturnBlock block4 = ^{
NSLog(@"%d", b);
};
NSLog(@"block被强指针指向 , type%@ ", [block4 class]);
///系统方法中有usesblock的字眼的, ARC下会默认copy到堆区
NSArray *arr = [NSArray array];
[arr enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
}];
///使用GCD中, ARC下会默认copy到堆区
}
- (ReturnBlock)getblock1 {
ReturnBlock block = ^{
NSLog(@"This is a block");
};
return block;
}
- (ReturnBlock)getblock2 {
int a = 10;
ReturnBlock block = ^{
NSLog(@"This is a block, a = %d", a);
};
return block;
}
@end
3. Block中对象类型的强引用和弱引用?
情形1一个block对实例对象person1强引用:
代码如下;
- (void)test0 {
TestBlock testblock;
{
Person *person1 = [[Person alloc] init];
testblock = ^{
NSLog(@"person1 : %@", person1);
};
}
testblock();
///block对person1强引用, 所以即使是出了{}作用域, 仍然可以打印出i其地址, 然后才会dealloc;
}
转换为C++
代码后的block
实现如下
struct __ViewController2__test0_block_impl_0 {
struct __block_impl impl;
struct __ViewController2__test0_block_desc_0* Desc;
///对person对象进行了强引用;
Person *__strong person1;
__ViewController2__test0_block_impl_0(void *fp, struct __ViewController2__test0_block_desc_0 *desc, Person *__strong _person1, int flags=0) : person1(_person1) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
情形2一个block对实例对象person2弱引用:
代码如下:
- (void)test1 {
TestBlock testblock;
{
Person *person2 = [[Person alloc] init];
__weak Person *weakPerson2 = person2;
testblock = ^{
NSLog(@"person2 : %@", weakPerson2);
};
}
testblock();
///block对weakPerson2弱引用,出了{}作用域后person2即销毁, 直接打印dealloc, 然后调用block时打印出的地址为null;
}
转换为C++
代码后的block
实现如下
struct __ViewController2__test1_block_impl_0 {
struct __block_impl impl;
struct __ViewController2__test1_block_desc_0* Desc;
///对weakPerson2进行了弱引用
Person *__weak weakPerson2;
__ViewController2__test1_block_impl_0(void *fp, struct __ViewController2__test1_block_desc_0 *desc, Person *__weak _weakPerson2, int flags=0) : weakPerson2(_weakPerson2) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
通过指令将OC文件转换为C++文件
指令:xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc 文件.m -o 文件-arm64.cpp
参考文章和下载链接
测试代码
iOS clang指令报错问题总结
Apple 一些源码的下载地址
auto修饰符
C++中结构体的构造函数
全局变量、静态全局变量、静态局部变量和普通局部变量的区别