美文网首页
block总结

block总结

作者: 细雨菲菲v | 来源:发表于2018-07-10 22:00 被阅读6次

1.block介绍

概念:block是将函数及其执行上下文封装起来的对象
下面将通过原码解析的方式理解概念
Objective-C代码如下:

-(void)method{
    int multiplier = 6;
    int(^Block)(int) = ^int(int num){
        return num * multiplier;
    };
    Block(2);
}

编译后的关键代码如下

 static void _I_MCBlock_method(MCBlock * self, SEL _cmd) {
    int multiplier = 6;
    /*
       int(^Block)(int) = ^int(int num){
        return num * multiplier;
      };
   */
     int(*Block)(int) = ((int (*) (int))&__MCBlock__method_block_impl_0((void *)__MCBlock__method_block_func_0, &__MCBlock__method_block_desc_0_DATA, multiplier));  

     __MCBlock__method_block_impl_0是一个结构体,传入三个参数,第一参数是函数指针__MCBlock__method_block_func_0,第二个参数是关于block相关描述的结构体,第三参数被block使用的局部变量。
从上面的代码可以看出block定义变量是一个函数指针。
    /*
       block(2)
    */
    ((int (*)(__block_impl *, int))((__block_impl *)Block)->FuncPtr)((__block_impl *)Block, 2);
}

__MCBlock__method_block_impl_0结构体的实现

struct __MCBlock__method_block_impl_0 {
  struct __block_impl impl;(结构体)
  struct __MCBlock__method_block_desc_0* Desc;(结构体)(关于block的相关描述)
  int multiplier;(block中使用的局部变量)
 /*c++当中对于结构体的构造函数的一个申明或者定义*/
  __MCBlock__method_block_impl_0(void *fp, struct __MCBlock__method_block_desc_0 *desc, int _multiplier, int flags=0) : multiplier(_multiplier) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;//标记位赋值
    impl.FuncPtr = fp;//函数指针赋值
    Desc = desc;//关于block描述的赋值
  }
};
 multiplier(_multiplier)将函数传递进来的_multiplier参数直接赋值给结构体中的multiplier变量

__block_impl 结构体的实现

struct __block_impl {
  void *isa;//isa指针,block是对象的标志
  int Flags;
  int Reserved;
  void *FuncPtr;//函数指针
};

关于__MCBlock__method_block_func_0

static int __MCBlock__method_block_func_0(struct __MCBlock__method_block_impl_0 *__cself, int num) {
  int multiplier = __cself->multiplier; // bound by copy
        return num * multiplier;
    }

2.block截获变量的特性

(1) block截获变量的特性需要分三种情况
1.局部变量

对于基本数据类型的局部变量截获其值,对于对象类型的局部 变量连同所有权修饰符一起截获。

2.局部静态变量

指针形式截获局部静态变量。

3.全局变量或者全局静态变量

不截获全局变量、静态全局变量。

(2)原码解析

Objective-C代码如下:

#import "MCBlock.h"

// 全局变量
int global_var = 4;
//静态全局变量
static int static_global_var = 5;

@implementation MCBlock

- (void)method
{
   //基本数据类型的局部变量
    int var = 1;
    //对象类型的局部变量
    __unsafe_unretained id unsafe_obj = nil;
    __strong id strong_obj = nil;
    
    //局部静态变量
    static int static_var = 3;
    void(^Block)(void) = ^{
        NSLog(@"局部变量<基本数据类型> var %d",var);
        NSLog(@"局部变量<unsafe_obj 对象类型> var %@",unsafe_obj);
        NSLog(@"局部变量<strong_obj 对象类型> var %@",strong_obj);
        NSLog(@"静态变量 %d",static_var);
        NSLog(@"全局变量 %d",global_var);
        NSLog(@"静态全局变量 %d",static_global_var);
    };
    Block(); 
}
@end

Objective-C编译后的主要代码如下:

int global_var = 4;
static int static_global_var = 5;
struct __MCBlock__method_block_impl_0 {
  struct __block_impl impl;
  struct __MCBlock__method_block_desc_0* Desc;
  // 截获局部变量的值
  int var;

 //  连同所有权修饰符一起截获
  __unsafe_unretained id unsafe_obj;
  __strong id strong_obj;
 //  以指针形式截获局部变量
  int *static_var;

 // 对全局变量、静态全局变量不截获

  __MCBlock__method_block_impl_0(void *fp, struct __MCBlock__method_block_desc_0 *desc, int _var, __unsafe_unretained id _unsafe_obj, __strong id _strong_obj, int *_static_var, int flags=0) : var(_var), unsafe_obj(_unsafe_obj), strong_obj(_strong_obj), static_var(_static_var) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

method对应的原码

static void _I_MCBlock_method(MCBlock * self, SEL _cmd) {
    int var = 1;
    __attribute__((objc_ownership(none))) id unsafe_obj = __null;
    __attribute__((objc_ownership(strong))) id strong_obj = __null;

    static int static_var = 3;

    void(*Block)(void) = ((void (*)())&__MCBlock__method_block_impl_0((void *)__MCBlock__method_block_func_0, &__MCBlock__method_block_desc_0_DATA, var, unsafe_obj, strong_obj, &static_var, 570425344));
    ((void (*)(__block_impl *))((__block_impl *)Block)->FuncPtr)((__block_impl *)Block);
}
(3)对应的题目
-(void)method{
    static int multiplier = 6;
    int (^Block)(int) = ^int (int num){
        return num * multiplier;
    };
    multiplier = 4;
    NSLog(@"result is %d",Block(2));
}
上述方法执行结果是 result is 8
-(void)method{
    int multiplier = 6;
    int (^Block)(int) = ^int (int num){
        return num * multiplier;
    };
    multiplier = 4;
    NSLog(@"result is %d",Block(2));
}
上述方法执行结果是 result is 12

3.__block修饰符

(1)使用说明及注意事项

使用说明:一般情况下,对被截获变量进行赋值操作需添加__block修饰符
对变量进行赋值需要分为两种情况:
1.基本数据类型和对象类型的局部变量需要__block修饰符;
2.静态局部变量、全局变量、静态全局变量不需要
注意:

截图.png
(1)使用误区

误区1(下面代码没有问题)

          NSMutableArray *array = [NSMutableArray array];
          void(^Block)(void) = ^{
             [array addObject:@123];
          };
          Block();
          NSLog(@"array=%@",array);
         以上代码是没有任何问题的

误区2

             NSMutableArray *array = nil;
              void(^Block)(void) = ^{
                array = [NSMutableArray array];
              };
            Block();
            NSLog(@"%@",array);
            编译会报错

误区2纠正写法

           __block    NSMutableArray *array = nil;
              void(^Block)(void) = ^{
                array = [NSMutableArray array];
              };
            Block();
            NSLog(@"%@",array);
(3)__block原理分析
    __block   int multiplier = 6;
    int (^Block)(int) = ^int (int num){
        return num * multiplier;
    };
    multiplier = 4;
    NSLog(@"result is %d",Block(2));
    上述方法执行结果是 result is 8

变量经过__block修饰后变成了对象,原码如下:

截图2.png
截图3.png

3.block的内存管理

(1)block分类

a._NSConcreteStackBlock 栈block
b._NSConcreteMallocBlock 堆block
c._NSConcreteGlobalBlock 全局block


截图4.png
(2)block的copy操作
截图5.png
截图7.png
(3)栈上block的销毁
截图6.png
(4)栈上__block变量的copy
截图8.png
(5)__forwarding总结

如果对__block没有进行copy操作,__forwarding操作的是栈上的__block变量,如果进行了copy操作,__forwarding操作的是堆上的__block变量。

 #import "ViewController.h"
 @interface ViewController ()

 @property (nonatomic,copy)int(^blk)(int);

 @end
 @implementation ViewController
 - (void)viewDidLoad {
     [super viewDidLoad];
   __block 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

5.block的循环引用

(1) 循环应用的例子
例子 a
     _array = [NSMutableArray arrayWithObject:@"block"];
     _stringBlock = ^NSString *(NSString *num){
         return [NSString stringWithFormat:@"helloc_%@",_array];
     };
    _stringBlock(@"hello");
截图9.png
解决方法:
    _array = [NSMutableArray arrayWithObject:@"block"];
    __weak NSArray *weakArray = _array;
    _stringBlock = ^NSString *(NSString *num){
        return [NSString stringWithFormat:@"helloc_%@",weakArray[0]];
    };
     _stringBlock(@"hello");
截图10.png
例子 b
    __block MCBlock *blockSelf = self;
    _blk = ^int(int num) {
        int result = num * blockSelf.var;
        return result;
    };
    _blk(3);
截图12.png
解决方法
    __block MCBlock *blockSelf = self;
    _blk = ^int(int num) {
        int result = num * blockSelf.var;
        blockSelf = nil
        return result;
    };
    _blk(3);
截图13.png

相关文章

网友评论

      本文标题:block总结

      本文链接:https://www.haomeiwen.com/subject/udnqpftx.html