理论
- 默认情况下, block的内存是在栈中,开发人员不需要去管理block内存,也就是代码一过掉,就不见了,相当于局部变量,局部变量都是在栈里面;它不会对所引用的对象进行任何操作。
- 如果对block做一次copy操作, block的内存就会在堆中,block里面的代码所引用的对象的计数器加1;
它会对所引用的对象做一次retain操作;
为什么不用retain,因为retain只是将block的计数器+1,并没有改变内存地址,因此不可能将block的内存地址从栈里面放到堆里面;
但是如果执行下面操作,不会做retain操作,计数器就不加1:
block防止循环引用:
非ARC : 如果所引用的对象用了__block
修饰, 就不会做retain操作,例如:__block typeof(self) VC = self;
ARC :如果所引用的对象用了'__unsafe_unretained'或者'__weak'修饰, 就不会做retain操作,例如:__unsafe_unretained typeof(self) = self;
__weak typeof(self) weakSelf = self;
在非ARC情况下,只是看计数器,没有强引用或者弱引用;
block实际上是: 指向结构体的指针
编译器会将block的内部代码生成对应的函数,
是否可以改变值,看是传递的值还是内存地址;
如果是传递的值,那就改不了值,例如是普通的局部变量,int a = 10;
以后就改不了值,如果是传递的是内存地址,以后就可以改变,例如__block int a = 10;
block就是弥补了指向函数的指针不能够直接保存一个函数体(代码块);
void (^myBlock)( ) = ^{
NSLog(@"test");
};
myBlock();
如果想要在block里面改变block代码块之外的变量值,就必须在声明变量前加入__block
关键字
__block int x = 0;
block在作为属性时用的是copy参数
如果block里面的代码用了外面的东西(通常是控制器),就会对外面的东西(通常是控制器)强引用.
因此,在外面新建一个弱指针,指引self(控制器),然后在block代码里面不要用self,而是用新建的弱指针:
__unsafe_unretained
或者__weak
,但是最好用__weak
,因为__weak
可以防止野指针错误,可以自动使对象为nil;
是一块预先准备好的代码,他可以当做参数传递;他是一种数据类型;
block的快捷键:inline block;
实践
可以达到代理的效果
// 无参数
typedef void(^SettingItemCompletion)();
@property (nonatomic, copy) SettingItemCompletion completion;
// 有参数
typedef void(^CardSelectedCompletion)(NSString *cardId);
@property (nonatomic, copy) CardSelectedCompletion completion;