什么是Block
1、 Block是将函数
及其执行上下文封装
起来的对象
。
{
int multiplier = 6;
int(^Block)(int) = ^int(int num) {
return num*multiplier;
};
Block(2);
}
2、 截获变量
局部变量:
基本数据类型
、对象类型
静态局部变量
全局变量
静态全局变量
对于
基本数据
类型的局部变量
截获其值。对于
对象
类型的局部变量连同所有权修饰符
-起截获。以
指针形式
截获局部静态变量不截获
全局变量、静态全局变量
{
int multiplier = 6;
int(^Block)(int) = ^int(int num) {
return num*multiplier;
};
multiplier = 4;
NSLog(@"结果=%d", Block(2));
}
那么这里的 结果就是12
{
static int multiplier = 6;
int(^Block)(int) = ^int(int num) {
return num*multiplier;
};
multiplier = 4;
NSLog(@"结果=%d", Block(2));
}
那么这里的 结果就是8
3、一般情况下
,对被截获变量进行赋值
操作需要添加__block修饰符
。
赋值 != 使用
这里就是使用
{
NSMutableArray *array = [NSMutableArray array];
void(^Block)(void) = ^{
[array addObject:@"123"];
};
Block();
}
这里就需要加__blcok, 这里就是赋值
{
__block NSMutableArray *array = nil;
void(^Block)(void) = ^{
array = [NSMutableArray array];
};
Block();
}
4、对变量进行赋值时
需要__block修饰符: 局部变量(基本数据类型、对象类型)。
不需要__block修饰符: 静态局部变量、全局变量、静态全局变量。
{
__block int multiplier = 6;
int(^Block)(int) = ^int(int num) {
return num*multiplier;
};
multiplier = 4;
NSLog(@"结果=%d", Block(2));
}
那么这里的 结果就是8
__block修饰的变量变成了对象
__block int multiplier
struct _Block_byref_mutiplier_0 {
void * _isa;
__Block_byref_multiplier_0 * __forwarding;
int __flags;
int __size;
int multiplier;
}
被修饰之后
multiplier = 4
相当于multiplier对象的__forwarding指针。指向multiplier。指向了自己。
(multiplier.__forwarding->multiplier) = 4
5、Block的内存管理
impl.isa = &_NSConcreteStackBlock;
- _NSConcreteGlobalBlock 全局类型Block
- _NSConcreteStackBlock 栈类型Block
- _NSConcreteMallocBlock 堆类型Block
Block的copy操作
Block类别 | 源 | copy结果 |
---|---|---|
�_NSConcreteGlobalBlock� | 数据区� | 什么也不做� |
�_NSConcreteStackBlock � | 栈 | 堆� |
�_NSConcreteMallocBlock� | 堆 | 增加引用计数� |
栈上的__forwarding
指向堆的Block。
堆上的__forwarding
指向堆自己的Block。
6、__forwarding总结
{
__blcok int multiplier = 10;
_blk = ^int(int num){
return num * multiplier;
};
multiplier = 6;
[self executeBlock];
}
- (void)executeBlock {
int result = _blk(4);
NSLog(@"result is %d", result);
}
result is 24
不论在任何内存位置, 都可以顺利的访问同一个__block变量。
7、循环引用
{
_array = [NSMutableArray arrayWithObject:@"123"];
_strBlock = ^NSString * (NSString * num ) {
return [NSString stringWithFormat:@"", _array];
};
_strBlock(@"123");
}
修改
{
_array = [NSMutableArray arrayWithObject:@"123"];
__weak NSArray * weakArray = _array;
_strBlock = ^NSString * (NSString * num ) {
return [NSString stringWithFormat:@"", weakArray];
};
_strBlock(@"123")l;
}
{
__block MCBlock * blockSelf = self;
_blok = ^int(int num){
// var = 2
int result = num * blockSelf.var;
blockSelf = nil;
return result;
};
_blk(3);
}
什么是Block?
答: Block是将函数及其上下文进行封装的对象。
为什么Block会产生循环引用?
答:如果当前Block对当前对象的成员变量进行截获,那么这个Block就对这个对象有浅引用。
这个对象也对Block有浅引用。就产生了自循环引用。
怎么理解Block截取变量的特性?
答:对于`基本数据类型`的`局部变量`,对`值`进行截获。
对于`对象类型`的`局部变量`连同所`有权修饰符`-起截获。也可以说强引用
对于静态的变量,对指针进行截获
对全局变量或者全局静态变量,都不截获
你遇到过哪些循环引用?你是怎么解决的?
答:Block截获的对象,也是当前对象的成员变量。自循环循环变量
用__block来解决,如果是自循环,那就可以是用断环的形式来避免。