1.什么是block?它的本质是什么?
block是一个结构体,可以封装一部分代码,block存储在栈区间,内部截获的变量存储在堆区间。
struct Block_layout {
void *isa;
int flags;
int reserved;
void (*invoke)(void *, ...);
struct Block_descriptor *descriptor;
};
isa:指向自身类的指针
flags:按bit位,表示一些block的附加信息
reserverd:保留变量
invoid:函数指针,block结构体定义后,实际上生成了一个函数,该函数指针指向block块
descriptor:描述block的信息,主要是size的大小,以及copy的函数指针
2.block的基础使用
1.在 Objective-C 语言中,一共有 3 种类型的 block:
_NSConcreteGlobalBlock 全局的静态 block,不会访问任何外部变量。
_NSConcreteStackBlock 保存在栈中的 block,当函数返回时会被销毁。
_NSConcreteMallocBlock 保存在堆中的 block,当引用计数为 0 时会被销毁。
2.修饰符:copy
copy:该block创建是在栈空间的,为什么方法执行用copy保存在堆空间
weak修饰:block存储在栈空间,在另外地方调用block时,已经销毁,造成野指针
3.block的使用场景
1.传值
A类定义block,在合适的地方,执行block块,B类在某事件中将值传出
2.block作为参数
作为开发者最熟悉的场景应该是网络请求,succes和failed后将值传出
3.block作为返回值
定义一个函数,让block作为返回值,这样就可以返回一个代码块
#import "Person.h"
@implementation Person
- (void (^)(int))dogs
{
return ^(int sums){
NSLog(@"%d",sums);
};
}
@end
在调用的时候,传入值
Person *per = [[Person alloc] init];
per.dogs(10);
4.链式编程
在代码块里面执行某些操作完成一些功能。返回自己,然后继续调用该函数,返回一个block,这样就可以实现masonry的链式调用效果
masnory
[View mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(anotherView);
make.left.equalTo(anotherView);
make.width.mas_equalTo(@60);
make.height.mas_equalTo(@60);
}];
eg:定义一个计算类,声明方法
- (Caculater * (^)(int))add
{
__weak Caculater *weakSelf = self;
return ^(int value){
weakSelf.result = weakSelf.result + value;
return weakSelf;
};
}
执行计算
Caculater *mgr = [[Caculater alloc] init];
mgr.result = 0;
mgr.add(5).add(6);
NSLog(@"%d", mgr.result);
结果输出
2018-07-09 15:31:50.962559+0800 BlcokReview[1855:189577] 11
5.函数式编程
定义计算类,声明方法
- (instancetype)addBlock:(int (^)(int))blcokName
{
_result = blcokName(_result);
return self;
}
- (instancetype)deteBlock:(int (^)(int))blcokName
{
_result = blcokName(_result);
return self;
}
执行计算
Caculater *mgr = [[Caculater alloc] init];
[[mgr addBlock:^int(int value) {
value += 5;
NSLog(@"%d", value);
return value;
}]deteBlock:^int(int value) {
value -= 3;
NSLog(@"%d", value);
return value;
}];
结果输出
2018-07-09 17:24:38.402167+0800 BlcokReview[2181:281962] 16
2018-07-09 17:24:38.402321+0800 BlcokReview[2181:281962] 13
4.block使用遇到的问题
1.循环引用
当一个对象持有了block后,block内部又使用了这个对象或者对象的实例变量、实例方法,这样会使block也持有这个对象,这样相互持有就是循环引用,从而导致对象无法释放引起内存泄露。
解决:
要解决循环引用只需要不要相互持有就行了,也就是说只需要一方持有就可以不让block再持有当前这个对象就OK。