1. block的本质和原理
block的本质实际上是OC对象,内部也存在着isa指针;
block 可作为代码块、函数的参数、返回值也可以代替代理;
block内部封装了函数调用地址 和 函数调用环境(函数的参数、所访问的外部属性值);
-
block底层是一个结构体(内部封装了函数调用地址 和 函数调用环境),结构体内部包含了两个结构体:
struct __block_impl impl; struct __main_block_desc_0 *Desc;
2.block中的循环引用
在 block(点语法)里面引用一个实例变量时,该实例对象会被 retain
解决循环引用的方式不同
MRC中使用__block(可修饰对象和基本数据类型)
ARC中使用 __weak(只可修饰对象)
3.为什么要用copy修饰
在MRC中,block默认是在栈上创建的。如果我们将它赋值给一个成员变量,如果成员变量没有被copy修饰或在赋值的时候没有进行copy,也就是局部变量离开作用域之后会被系统回收,那么在使用这个block成员变量的时候就会崩溃。
在MRC中, 定义Block属性时, 应该用copy修饰。在ARC中, 定义Block属性时, 系统会自动将其copy, 即复制到堆上.
用copy修饰的原因:block创建时默认是创建在栈上的, 超过作用域后就会被销毁, 只有使用copy才会生成一个堆block, 在作用域外被访问
4.block的类型
三种类型:
NSGlobalBlock:常量、静态创建的block
NSMallocBlock:在进程堆上分配的Block,动态创建的Block(引用外部常量或者变量的,MRC下调用copy的)。
NSStackBlock:进程栈上分配的Block,动态创建的Block。
void(^blockA)(void) = ^{
NSLog(@"just a block");
};
NSLog(@"%@", blockA);
int value = 10;
void(^blockB)(void) = ^{
NSLog(@"just a block === %d", value);
};
NSLog(@"%@", blockB);
void(^ __weak blockC)(void) = ^{
NSLog(@"just a block === %d", value);
};
NSLog(@"%@", blockC);
void(^ __weak blockD)(void) = ^{
NSLog(@"just a block");
};
NSLog(@"%@", blockD);
2020-07-08 16:13:42.285554+0800 EAccountDemo[20034:4129159] <__NSGlobalBlock__: 0x1046351a0>
2020-07-08 16:13:42.285628+0800 EAccountDemo[20034:4129159] <__NSMallocBlock__: 0x281632be0>
2020-07-08 16:13:42.285688+0800 EAccountDemo[20034:4129159] <__NSStackBlock__: 0x16b90d1f0>
2020-07-08 16:13:42.285738+0800 EAccountDemo[20034:4129159] <__NSGlobalBlock__: 0x1046351e0>