一、Block的几种写法
1、有返回值、有参数列表
先介绍一下Block语法的书写,首先来看一个完整的Block:
int (^ExistReturnValueWithExistParameterBlock)(int num);
// “^”这个符号表示这是一个Block;
// 返回值:int表示返回值类型
// 变量名:ExistReturnValueWithExistParameterBlock
// 参数列表:(int num)这个括号中是Block的参数
ExistReturnValueWithExistParameterBlock = ^ int(int num){
NSLog(@"有参数列表,参数为:%d,有返回值,返回值为:%d",num,300+num);
return 300+num;
};
ExistReturnValueWithExistParameterBlock(500);
打印结果:有参数列表,参数为:500,有返回值,返回值为:800
也可以省略不写Block的返回值,例如以下写法:
int (^ExistReturnValueWithExistParameterBlock)(int num);
ExistReturnValueWithExistParameterBlock = ^(int num){
return 300+num;
};
ExistReturnValueWithExistParameterBlock(500);
2、没有返回值,没有参数列表
完整写法①:
void (^NoReturnValueWithNoParameterBlock)(void) = ^void(void) {
NSLog(@"没有返回值,没有参数列表");
};
NoReturnValueWithNoParameterBlock();
打印结果:没有返回值,没有参数列表
完整写法②:
void (^NoReturnValueWithNoParameterBlock)(void);
NoReturnValueWithNoParameterBlock = ^void(void) {
NSLog(@"没有返回值,没有参数列表");
};
NoReturnValueWithNoParameterBlock();
简略写法①:
void (^NoReturnValueWithNoParameterBlock)() = ^ {
NSLog(@"没有返回值,没有参数列表");
};
NoReturnValueWithNoParameterBlock();
简略写法②:
void (^NoReturnValueWithNoParameterBlock)();
NoReturnValueWithNoParameterBlock = ^ {
NSLog(@"没有返回值,没有参数列表");
};
NoReturnValueWithNoParameterBlock();
3、没有返回值,有参数列表
完整写法①:
void(^ExistParameterBlock)(int num) = ^(int num){
NSLog(@"没有返回值,有参数列表,参数为:%d",num);
};
ExistParameterBlock(100);
打印结果:没有返回值,有参数列表,参数为:100
完整写法②:
void(^ExistParameterBlock)(int num);
ExistParameterBlock = ^(int num){
NSLog(@"没有返回值,有参数列表,参数为:%d",num);
};
ExistParameterBlock(100);
4、有返回值、没有参数列表
完整写法:
int(^ExistReturnValueBlock)();
ExistReturnValueBlock = ^ int{
return 200;
};
NSLog(@"没有参数列表,有返回值,返回值为:%d",ExistReturnValueBlock());
打印结果:没有参数列表,有返回值,返回值为:200
二、Block改变外部变量的值
1、非集合对象
int value = 11;
void (^changeValueBlock)() = ^{
value = 33;
};
这段代码编译出错,编译器提示的大概就是不能在Block中改变变量的值。因为在Block中截获了变量的瞬间值以后就不能再改变变量的值,如果想要在Block中改变变量的值,那么我们只需要在变量声明的时候加上__block修饰符。
如下:
__block int value = 11;
NSLog(@"value改变之前:%d", value);
void (^changeValueBlock)() = ^{
value = 33;
};
changeValueBlock();
NSLog(@"value改变之后:%d", value);
打印结果:value改变之前:11
打印结果:value改变之后:33
2、集合对象
和非集合对象不一样。对于集合对象,因为我们只是对截获的变量进行了操作,而没有进行赋值,所以对于截获变量,可以进行操作而不可以进行赋值。
NSMutableArray *array = [[NSMutableArray alloc]init];
NSLog(@"array改变之前:%@", array);
void (^changeArrayBlock)() = ^{
[array addObject:@"block"];
};
changeArrayBlock();
NSLog(@"array改变之后:%@", array);
打印结果:array改变之前:( )
打印结果:array改变之后:( block, )
三、Block当作函数参数
具体代码如下:
//
// SecondViewController.m
//
#import "SecondViewController.h"
typedef void(^ParameterBlock)(NSString *str);
@interface SecondViewController ()
@end
@implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
//Block当作函数参数
[self testBlockMethod:^(NSString *str) {
NSLog(@"%@",str);
}];
}
- (void)testBlockMethod:(ParameterBlock)block {
block(@"测试block为函数参数");
}
@end
四、Block逆向传值
在APP页面跳转过程,如果A 页面--> B页面是正向的话,那么我们把B页面的值传给A就叫做 反向传值、逆向传值(或者叫做回调)。
首先建立两个控制器HomeViewController(A)和TestViewController(B),HomeViewController(A) 跳转到TestViewController(B) 。HomeViewController(A)作为捕获方,TestViewController(B)作为传值方。
1、传值方---TestViewController(B)
TestViewController.h文件
//
// TestViewController.h
//
// 谁传值,谁就写block
#import <UIKit/UIKit.h>
typedef void(^TransmitBlock)(NSString *title);
@interface TestViewController : UIViewController
@property (nonatomic, copy) TransmitBlock block;
@end
TestViewController.m文件
//
// TestViewController.m
//
#import "TestViewController.h"
@interface TestViewController ()
@property (nonatomic, strong) UIButton *testBtn;
@end
@implementation TestViewController
- (void)viewDidLoad {
[super viewDidLoad];
_testBtn = [[UIButton alloc]initWithFrame:CGRectMake(200, 200, 55, 55)];
[self.view addSubview:_testBtn];
_testBtn.backgroundColor = [UIColor redColor];
[_testBtn setTitle:@"点击" forState:UIControlStateNormal];
[_testBtn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
[_testBtn addTarget:self action:@selector(clickedBtn) forControlEvents:UIControlEventTouchUpInside];
}
- (void)clickedBtn {
self.block(@"block测试");
}
@end
2、捕获方---HomeViewController(A)
HomeViewController.m文件
//
// HomeViewController.m
//
#import "HomeViewController.h"
#import "TestViewController.h"
@interface HomeViewController ()
@property (nonatomic, strong) UILabel *titleLab;
@property (nonatomic, strong) UIButton *clickBtn;
@end
@implementation HomeViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.titleLab = [[UILabel alloc]initWithFrame:CGRectMake(200, 100, 100, 30)];
[self.view addSubview:self.titleLab];
self.titleLab.backgroundColor = [UIColor yellowColor];
self.titleLab.textColor = [UIColor blueColor];
self.titleLab.font = [UIFont systemFontOfSize:20.0];
self.clickBtn = [[UIButton alloc]initWithFrame:CGRectMake(200, 200, 55, 55)];
[self.view addSubview:self.clickBtn];
self.clickBtn.backgroundColor = [UIColor redColor];
[self.clickBtn setTitle:@"跳转" forState:UIControlStateNormal];
[self.clickBtn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
[self.clickBtn addTarget:self action:@selector(jumpToTestVC) forControlEvents:UIControlEventTouchUpInside];
}
- (void)jumpToTestVC {
TestViewController *testVC = [[TestViewController alloc]init];
__weak typeof(self) weakself = self;
testVC.block = ^(NSString *title){
__strong typeof(weakself) strongSelf = weakself;
strongSelf.titleLab.text = title;
};
// weakSelf是为了block不持有self,避免循环引用,而再声明一个strongSelf是因为一旦进入block执行,就不允许self在这个执行过程中释放。block执行完后这个strongSelf会自动释放,没有循环引用问题。
[self.navigationController pushViewController:testVC animated:YES];
}
@end
网友评论