iOS Block基本使用(一)

2021-03-17  本文已影响0人  学不来的凡人

什么是Block?
Block 又称为“块” 或 “代码块”,作用是用来保存代码,保存在其内部的代码块 如果Block不被调用 这段代码就不会执行
在OC中Block的基本格式是这样的

返回值类型  (^block名)  (参数类型 和 数量) = ^(形参 和 数量){   
   //code 
};

Block的本质上也是一个OC对象 它内部也有个isa指针
Block是封装了函数调用以及函数调用环境(比如参数和返回值)的OC对象
Block是封装了函数及其上下文的OC对象

1、写一个简单的block:

    @autoreleasepool {
        appDelegateClassName = NSStringFromClass([AppDelegate class]);
        MyBlock myBlock = ^{
        };
        NSLog(@"myBlock:%@",myBlock);//myBlock:<__NSGlobalBlock__: 0x10bfde038>
        myBlock();
    }

转成底层代码

typedef void(*MyBlock)(void);
//Block的本质
struct __block_impl {
  void *isa;//isa指针(Block的类型-->指向Class)
  int Flags;
  int Reserved;
  void *FuncPtr;//封装代码块的地址
};

struct __test_block_impl_0 {
  struct __block_impl impl;
  struct __test_block_desc_0* Desc;
// 构造函数(类似于OC的init方法),返回结构体对象
  __test_block_impl_0(void *fp, struct __test_block_desc_0 *desc, int flags=0) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
static void __test_block_func_0(struct __test_block_impl_0 *__cself) {

}

static struct __test_block_desc_0 {
  size_t reserved;
  size_t Block_size;
} __test_block_desc_0_DATA = { 0, sizeof(struct __test_block_impl_0)};
void test(){
    MyBlock myBlock = ((void (*)())&__test_block_impl_0((void *)__test_block_func_0, &__test_block_desc_0_DATA));


    ((void (*)(__block_impl *))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock);

}

2、block内部捕获变量

int a_q = 10;//全局变量
static int b_q = 10;//全局静态变量
typedef void(^MyBlock)(void);
void test(){
    int a = 10;//局部变量
    static int b = 10;//局部静态变量
    MyBlock myBlock = ^{
        NSLog(@"a=%d", a);//a=10
        NSLog(@"b=%d", b);//b=20
        NSLog(@"a_q=%d", a_q);//a_q=20
        NSLog(@"b_q=%d", b_q);//b_q=20
    };
    a = 20;
    b = 20;
    a_q = 20;
    b_q = 20;
    myBlock();
}

转成底层代码

typedef void(*MyBlock)(void);
//Block的本质
struct __block_impl {
  void *isa;//isa指针(Block的类型-->指向Class)
  int Flags;
  int Reserved;
  void *FuncPtr;//封装代码块的地址
};
int a_q = 10;
static int b_q = 10;
typedef void(*MyBlock)(void);

struct __test_block_impl_0 {
  struct __block_impl impl;
  struct __test_block_desc_0* Desc;
  int a;
  int *b;
  __test_block_impl_0(void *fp, struct __test_block_desc_0 *desc, int _a, int *_b, int flags=0) : a(_a), b(_b) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
static void __test_block_func_0(struct __test_block_impl_0 *__cself) {
  int a = __cself->a; // bound by copy
  int *b = __cself->b; // bound by copy

        NSLog((NSString *)&__NSConstantStringImpl__var_folders_r0_rjxg_z6540vblvmqqv4klgsm0000gn_T_main_df2751_mi_0, a);
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_r0_rjxg_z6540vblvmqqv4klgsm0000gn_T_main_df2751_mi_1, (*b));
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_r0_rjxg_z6540vblvmqqv4klgsm0000gn_T_main_df2751_mi_2, a_q);
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_r0_rjxg_z6540vblvmqqv4klgsm0000gn_T_main_df2751_mi_3, b_q);
    }

static struct __test_block_desc_0 {
  size_t reserved;
  size_t Block_size;
} __test_block_desc_0_DATA = { 0, sizeof(struct __test_block_impl_0)};
void test(){
    int a = 10;
    static int b = 10;
    MyBlock myBlock = ((void (*)())&__test_block_impl_0((void *)__test_block_func_0, &__test_block_desc_0_DATA, a, &b));
    a = 20;
    b = 20;
    a_q = 20;
    b_q = 20;
    ((void (*)(__block_impl *))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock);
}

分析:
1、局部变量a:可以看到我们Block内部有一个(int _a)变量,局部变量a直接传值给_a;(在局部变量中 auto局部变量出了作用域就会销毁 为了避免执行block时 变量不存在 所以auto变量在Block内部被直接赋值为当前值)
2、局部静态变量b:可以看到我们Block内部有一个(int _b)变量,局部静态变量b把b(指针)传给*_b;(static变量一直存在于内存中不必有此担忧,所以存储的是变量指针,可以随时取出最新值。)
3、全局变量a_q和全局静态变量b_q:Block内部没有生成对应的变量(如果是全局变量 Block使用时不用捕获 直接访问 所以得到的也全部都是最新值。)
总结:局部变量之所以需要捕获 因为我们是跨函数使用的 声明和使用不是在一个作用域内
注意:self这个变量也是局部变量 也会被block捕获,因为在OC中所有的方法编译后都是自带两个参数 一个是实例对象 一个是SEL _cmd
所以Block中如果用到self,self也会被捕获。且Block内部的self属性 指向我们传进去的self
所以 我们也能理解为什么会造成循环引用了吧。

self捕获

int a_q = 10;
static int b_q = 10;
typedef void(^MyBlock)(void);
- (void)test{
    int a = 10;
    static int b = 10;
    MyBlock myBlock = ^{
        NSLog(@"a=%d", a);//a=10
        NSLog(@"b=%d", b);//b=20
        NSLog(@"a_q=%d", a_q);//a_q=20
        NSLog(@"b_q=%d", b_q);//b_q=20
        NSLog(@"%@",self);
    };
    a = 20;
    b = 20;
    a_q = 20;
    b_q = 20;
    myBlock();
}

转成底层代码

int a_q = 10;
static int b_q = 10;
typedef void(*MyBlock)(void);

struct __ViewController__test_block_impl_0 {
  struct __block_impl impl;
  struct __ViewController__test_block_desc_0* Desc;
  int a;
  int *b;
  ViewController *self;
  __ViewController__test_block_impl_0(void *fp, struct __ViewController__test_block_desc_0 *desc, int _a, int *_b, ViewController *_self, int flags=0) : a(_a), b(_b), self(_self) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
static void __ViewController__test_block_func_0(struct __ViewController__test_block_impl_0 *__cself) {
  int a = __cself->a; // bound by copy
  int *b = __cself->b; // bound by copy
  ViewController *self = __cself->self; // bound by copy

        NSLog((NSString *)&__NSConstantStringImpl__var_folders_r0_rjxg_z6540vblvmqqv4klgsm0000gn_T_ViewController_16af55_mi_0, a);
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_r0_rjxg_z6540vblvmqqv4klgsm0000gn_T_ViewController_16af55_mi_1, (*b));
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_r0_rjxg_z6540vblvmqqv4klgsm0000gn_T_ViewController_16af55_mi_2, a_q);
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_r0_rjxg_z6540vblvmqqv4klgsm0000gn_T_ViewController_16af55_mi_3, b_q);
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_r0_rjxg_z6540vblvmqqv4klgsm0000gn_T_ViewController_16af55_mi_4,self);
    }
static void __ViewController__test_block_copy_0(struct __ViewController__test_block_impl_0*dst, struct __ViewController__test_block_impl_0*src) {_Block_object_assign((void*)&dst->self, (void*)src->self, 3/*BLOCK_FIELD_IS_OBJECT*/);}

static void __ViewController__test_block_dispose_0(struct __ViewController__test_block_impl_0*src) {_Block_object_dispose((void*)src->self, 3/*BLOCK_FIELD_IS_OBJECT*/);}

static struct __ViewController__test_block_desc_0 {
  size_t reserved;
  size_t Block_size;
  void (*copy)(struct __ViewController__test_block_impl_0*, struct __ViewController__test_block_impl_0*);
  void (*dispose)(struct __ViewController__test_block_impl_0*);
} __ViewController__test_block_desc_0_DATA = { 0, sizeof(struct __ViewController__test_block_impl_0), __ViewController__test_block_copy_0, __ViewController__test_block_dispose_0};

static void _I_ViewController_test(ViewController * self, SEL _cmd) {
    int a = 10;
    static int b = 10;
    MyBlock myBlock = ((void (*)())&__ViewController__test_block_impl_0((void *)__ViewController__test_block_func_0, &__ViewController__test_block_desc_0_DATA, a, &b, self, 570425344));
    a = 20;
    b = 20;
    a_q = 20;
    b_q = 20;
    ((void (*)(__block_impl *))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock);
}

上一篇 下一篇

猜你喜欢

热点阅读