block的定义
// 无参无返回
void(^block)();
// 无参有返回
int(^block1)();
// 有参有返回
int(^block1)(int number);
也可以直接打入inline
来自动生成block格式
<#returnType#>(^<#blockName#>)(<#parameterTypes#>) = ^(<#parameters#>) {
<#statements#>
};
block的循环引用
- 如果要在block中直接使用外部强指针会发生错误,使用以下代码在block外部实现可以解决
__weak typeof(self) weakSelf = self;
- 但是如果在block内部使用延时操作还使用弱指针的话会取不到该弱指针,需要在block内部再将弱指针强引用一下
__strong typeof(self) strongSelf = weakSelf;
block的内存管理
- 无论当前环境是ARC还是MRC,只要block没有访问外部变量,block始终在全局区
- MRC情况下
1.block如果访问外部变量,block在栈里
2.不能对block使用retain,否则不能保存在堆里
3.只有使用copy,才能放到堆里 - ARC情况下
1.block如果访问外部变量,block在堆里
2.block可以使用copy和strong,并且block是一个对象
通过block来传值
- 在控制器间传值可以使用代理或者block,使用block相对来说简洁
在前一个控制器的touchesBegan:
方法内实现如下代码
ModalViewController *modalVc = [[ModalViewController alloc] init];
modalVc.valueBlcok = ^(NSString *str){
NSLog(@"ViewController拿到%@",str);
};
[self presentViewController:modalVc animated:YES completion:nil];
**在ModalViewController
控制器的.h
文件中声明一个block属性 **@property (nonatomic ,strong) void(^valueBlcok)(NSString *str);
并在.m
文件中实现方法
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
// 传值:调用block
if (_valueBlcok) {
_valueBlcok(@"123");
}
}
这样在ModalViewController
回到上一个控制器的时候,上一个控制器的label
就能显示ModalViewController
传过来的字符串
block作为一个参数使用
新建一个类,在.h
文件中声明一个方法- (void)calculator:(int(^)(int result))block;
并在.m
文件中实现该方法
- (void)calculator:(int (^)(int))block
{
self.result = block(self.result);
}
在其他类中调用该方法
CalculatorManager *mgr = [[CalculatorManager alloc] init];
[mgr calculator:^(int result){
result += 5;
return result;
}];
block作为返回值使用
在masonry
框架中我们可以看到如下用法make.top.equalTo(superview.mas_top).with.offset(padding.top);
这个方法实现就是将block作为返回值来使用
来分析一下这段代码
其实可以将这段代码看成make.top
,make.equalTo
,make.with
,make.offset
,所以可以得出一个结论是make.top
返回了一个make
,才能实现make.top.equalTo
**那来模仿一下这种功能的实现** 新建一个类,在
.h文件中声明一个方法
- (CalculatorManager *(^)(int a))add;```
在.m
文件中实现方法
- (CalculatorManager * (^)(int a))add
{
return ^(int a){
_result += a;
return self;
};
}
这样就可以在别的类中实现上面代码的用法
mgr.add(1).add(2).add(3);
block的变量传递
- 如果block访问的外部变量是局部变量,那么就是值传递,外界改了,不会影响里面
- 如果block访问的外部变量是
__block
或者static
修饰,或者是全局变量,那么就是指针传递,block里面的值和外界同一个变量,外界改变,里面也会改变
验证一下是不是这样
通过Clang
来将main.m
文件编译为C++
在终端输入如下命令clang -rewrite-objc main.m
void(*block)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_a_0 *)&a, 570425344));
void(*block)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a));
可以看到在编译后的代码最后可以发现被__block
修饰过得变量使用的是&a
,而局部变量是a
还在学习中,有错误请指出,谢谢!!