block声明/定义
- block的作用:保存一段代码
// 声明:返回值(^block变量名)(参数)
void(^block)();
// 定义
// 方式一:
void(^block1)() = ^(){
NSLog(@"调用block1");
};
// 调用Block,就会去查看下Block保存代码
block1();
// 方式二:block如果没有参数,可以省略()
// void(^)()
void(^block2)() = ^{
};
// 方式三:block定义中,返回值可以省略
// 类型:int(^)()
int(^block3)() = ^int{
return 2;
};
添加block属性
// Block怎么声明.就怎么定义属性
// block:属性名
@property (nonatomic ,strong) void(^block)();
block内存管理(非ARC)
-
首先了解内存的五大区:
- 堆:需要手动管理内存
- 栈:不需要手动管理内存,代码块一过,会自动清空栈里面内存
- 方法区(代码区)
- 全局区(静态区)
- 常量区
-
如何判断非ARC环境:
- 重写dealloc,调用super,ARC中不能调用[super dealloc]
- 判断下是否可以调用retain,release等等
-
非ARC开发中注意
- 访问属性,不要直接使用_,而是set,get方法去访问
- 非ARC中没有weak-->assign ,strong-->retain
block是对象吗?官方文档,block是对象
-
非ARC环境,block怎么去管理内存
- block没有访问外部局部变量的时候,存放到全局区
- block访问了外部局部变量,block放到栈里面
- 只要block访问的变量,是整个app都在的变量,那么肯定在全局区
- 在非ARC中,不能使用retain引用Block,使用retain之后不会将block放在堆中,在非ARC中只能使用copy,才会把block放在堆中
block内存管理(非ARC)
- block访问外部局部变量,block存放堆里面
- 可以使用strong去引用
- ARC中,默认局部对象变量都是强指针,但是如果没有其他强指针引用的话过了代码所在的大括号就会被销毁
block循环引用
- (void)viewDidLoad {
[super viewDidLoad];
int a = 0;
// Block循环引用,跟block调用没有关系
// block只要访问外部强指针对象变量,就会对这个变量进行强引用.
__weak typeof(self) weakSelf = self;
_block = ^{
__strong typeof(weakSelf) strongSelf = weakSelf;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2* NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"延迟打印%@",strongSelf);
});
};
_block();
}
set方法内存管理
- retain需要使用的对象
- release之前的对象
- 只有传入的对象和之前的不同才需要release和retain
- (void)setRoom:(Room *)room
{
// 避免过度释放
if (room != _room)
{
// 对当前正在使用的房间(旧房间)做一次release
[_room release];
// 对新房间做一次retain操作
_room = [room retain];
}
}
block变量传递
//打印结果为5:值传递
- (void)viewDidLoad {
[super viewDidLoad];
int a = 5;
void(^block)() = ^{
NSLog(@"%d",a);
};
a = 10;
block();
}
//打印结果为10:指针传递
- (void)viewDidLoad {
[super viewDidLoad];
static int a = 5;
void(^block)() = ^{
NSLog(@"%d",a);
};
a = 10;
block();
}
//打印结果为10:指针传递
- (void)viewDidLoad {
[super viewDidLoad];
__block int a = 5;
void(^block)() = ^{
NSLog(@"%d",a);
};
a = 10;
block();
}
//打印结果为10,指针传递
static int a = 5;
- (void)viewDidLoad {
[super viewDidLoad];
void(^block)() = ^{
NSLog(@"%d",a);
};
a = 10;
block();
}
- 总结:当是全局变量,或者局部变量被static或__block修饰,那么block块访问外界变量就是指针传递,普通的局部变量就是值传递
block当做参数去使用
- 为什么要把block当做参数去使用
- 使用场景: 当自己封装一个类的时候,有些事情由外部决定,但是什么时候去做,由内部决定,这时候采取使用block
- 需求:封装一个计算器,提供一个计算方法,怎么计算由外界去决定,什么时候计算,自己管理
//控制器当中的代码
- (void)viewDidLoad {
[super viewDidLoad];
//创建一个计算器管理者
CalculateManager *manager = [[CalculateManager alloc] init];
[manager calculateManager:^(int result){
result = result + 5;
result = result * 5;
return result;
}];
NSLog(@"%d",manager.result);
}
//计算机管理者类当中提供的方法,_result为管理者的属性
-(void)calculateManager:(int(^)(int))block
{
//相当于执行
// ^(_result){
// result = result + 5;
// result = result * 5;
// return result;
// }
_result = block(_result);
}
block当做参数返回
- 以后只要看到调用方法后面接(),就是把block当做返回值去使用
- (void)viewDidLoad {
CalculateManager *manager = [[CalculateManager alloc] init];
//让计算器不断的累加
manager.add(5).add(5).add(5).add(5);
NSLog(@"%zd",manager.result);
}
-(CalculateManager *(^)(NSInteger))add
{
return ^(NSInteger value){
_result += value;
return self;
};
}