block的基本理解

什么是Block

1、 Block是将函数及其执行上下文封装起来的对象

{ 
      int multiplier = 6;
      int(^Block)(int) = ^int(int num) {
            return num*multiplier;
      };
      Block(2);
}
BLOCK.png

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� 增加引用计数�
栈上的Block进行copy之后变成堆

栈上的__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);
}
image.png
什么是Block?
答: Block是将函数及其上下文进行封装的对象。

为什么Block会产生循环引用?
答:如果当前Block对当前对象的成员变量进行截获,那么这个Block就对这个对象有浅引用。
   这个对象也对Block有浅引用。就产生了自循环引用。

怎么理解Block截取变量的特性?
答:对于`基本数据类型`的`局部变量`,对`值`进行截获。
   对于`对象类型`的`局部变量`连同所`有权修饰符`-起截获。也可以说强引用
   对于静态的变量,对指针进行截获
   对全局变量或者全局静态变量,都不截获

你遇到过哪些循环引用?你是怎么解决的?
答:Block截获的对象,也是当前对象的成员变量。自循环循环变量
      
      用__block来解决,如果是自循环,那就可以是用断环的形式来避免。

你可能感兴趣的:(block的基本理解)