基本使用
声明
- 返回值(^block变量名)(参数)
void(^block)();
定义
第一种
void(^block)() = ^(){
};
第二种
- 如果没有参数,参数可以隐藏,如果有参数,定义的时候必须要写参数,而且必须要有参数变量名
void(^block)(int) = ^(int a){
};
第三种
- block返回可以省略,不管有没有返回值,都可以省略
int(^block)() = ^int{
return 0;
};
类型:int(^)(NSString *)
int(^block)(NSString *) = ^(NSString *name){
return 0;
};
调用
block();
快捷方式 敲inline直接回车
<#returnType#>(^<#blockName#>)(<#parameterTypes#>) = ^(<#parameters#>) {
<#statements#>
};
block属性
@property (nonatomic, strong) void(^block)();
void(^block)() = ^{
};
开发场景
保存代码
- 在一个类中定义,在另外一个类中调用
//一个类定义
@property (nonatomic, strong) void(^block)();
//另外一个类调用
item.block = ^{
};
代理传值
传值:
1.只要能拿到对方就能传值
- 顺传:给需要传值的对象,直接定义属性就能传值
- 逆传:用代理,block,就是利用block去代替代理
- 我们想让ModalViewControll给ViewControll传值,我们可以使用代理
ModalViewControll类中.h声明
@class ModalViewControll
@protocol ModalViewControllDelegate <NSObject>
@optional
//设计方法:想让代理做什么事情
-(void)modalViewControll:(modalViewControll *)modalVc sendValue:(NSString *)value;
@end
@property(nonatomic, weak) id<ModalViewControllDelegate> delegate;
ModalViewControll类中.m实现
//我们把动作设成点击ModalViewControll控制器给ViewControll传值
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//传值给ViewControll
if ([_delegate respondsToSelector:@selector(modalViewControll:sendValue:)]){
[_delegate modalViewControll:self sendValue:@"123"];
}
}
- 123就是我们给ViewControll传的值
在ViewControll.m中实现
//1.遵守协议<ModalViewControllDelegate>
//2.设置代理为ViewControll控制器
ModalViewControll moadlVc = [[ModalViewControll alloc] init];
modalVc.delegate = self;
//实现代理方法
-(void)modalViewControll:(ModalViewControll *)modalVc sendValue:(NSString *)value{
NSLog(@"%@", value);
}
block传值(推荐使用block进行逆传值)
ModalViewControll类中.h声明
@property (nonatomic, strong) void(^block)(NSString *value);
ModalViewControll类中.m实现
//我们把动作设成点击ModalViewControll控制器给ViewControll传值
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//传值给ViewControll
if (_block){
_block(@"123");
}
}
在ViewControll.m中实现
ModalViewControll moadlVc = [[ModalViewControll alloc] init];
modal.block = ^(NSString *value){
NSLog(@"%@", value);
};
参数使用
- 怎么区分参数是block,就看有没有,只要有,把block当作参数
- 把block当作参数,并不是马上就调用block,什么时候调用,由方法内部决定
- 什么时候需要把block当作参数去使用:做的事情由外界决定,但是什么时候做由内部决定
需求:封装一个计算器,提供一个计算方法,怎么计算由外界决定,什么时候计算由内部决定
1.创建一个计算器管理者(CacultorManager)
在CacultorManager.h中实现
//用来保存计算的结果
@property(nonatomic,assign) NSInteger result;
-(void)cacultor:(NSInteger (^) (NSInteger result)) block;
在CacultorManager.m中实现
-(void)cacultor:(NSInteger (^)(NSInteger))block{
if (block) {
_result = block(_result);
}
}
在ViewController.m中实现
//创建计算器管理者
CacultorManager *cacultor = [[CacultorManager alloc] init];
[cacultor cacultor:^NSInteger(NSInteger result) {
result += 5;
return result;
}];
NSLog(@"%ld",cacultor.result);
返回值
- 链式编程思想:把所有的语句用.号连接起来,好处:可读性非常好
- (void)viewDidLoad{
[super viewDidLoad];
//只有返回值是block,我们才可以写成这个样子调用
self.test();
}
-(void(^)())test{
return ^{
NSLog(@"调用了block");
};
}
需求:封装一个计算器,提供一个计算方法(加法)
1.创建一个计算器管理者(CacultorManager)
在CacultorManager.h中实现
//用来保存计算的结果
@property(nonatomic,assign) NSInteger result;
-(CacultorManager *(^)(int))add;
在CacultorManager.m中实现
return ^(int value){
_result = _result + value;
return self;
};
在ViewController.m中实现
//创建计算器管理者
CacultorManager *cacultor = [[CacultorManager alloc] init];
cacultor.add(5).add(5).add(5);
NSLog(@"%ld",cacultor.result);
内存管理
面试
- block是一个对象
- 如何判断当前文件是MRC,还是ARC
1.dealloc 能否调用super,只有MRC才能调用super
2.能否使用retain, release。如果能用就是MRC - ARC管理原则:只要一个对象没有被强指针修饰就会被销毁,默认局部变量对象都是强指针,存放在堆里面
- MRC开发常识:
1.MRC没有strong,weak,局部变量对象就是相当于基本数据类型
2.MRC给成员属性赋值,一定要使用set方法,不能直接访问下划线成员属性赋值
MRC:管理block
- 只要是block没有引用外部局部变量,block放在全局区(和环境没有关系)
- 只要block引用外部局部变量,block放在栈里面
- block只能使用copy,不能使用retain,使用retain,block还是在栈里面,使用copy在堆里面
ARC:管理block
- 只要是block没有引用外部局部变量,block放在全局区(和环境没有关系)
- 只要block引用外部局部变量,block放在堆里面
- block使用strong,最好不用copy
循环引用
- block造成循环引用:block会对里面所有强指针变量都强引用一次
- 解决
@property (nonatomic, strong) void(^block)();
__weak typrof(self) weakSelf = self;
_block = ^{
NSLog(@"%@", weakSelf);
};
变量传递
- 如果是局部变量,block是值传递
- 如果是静态变量,全局变量,__block修饰的变量,block都是指针传递