美文网首页
iOS Block基本使用(一)

iOS Block基本使用(一)

作者: 学不来的凡人 | 来源:发表于2021-03-17 13:52 被阅读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);
}

相关文章

  • iOS Block存储域及循环引用

    系列文章:iOS Block概念、语法及基本使用iOS Block实现原理iOS Block __block说明符...

  • iOS Block实现原理

    系列文章:iOS Block概念、语法及基本使用iOS Block __block说明符iOS Block存储域及...

  • iOS Block __block说明符

    系列文章:iOS Block概念、语法及基本使用iOS Block实现原理iOS Block存储域及循环引用 上一...

  • block的使用和注意

    iOS学习-(1)block的使用和注意 本文简介 本文主要介绍1.block的基本使用 ...

  • iOS Block基本使用(一)

    什么是Block?Block 又称为“块” 或 “代码块”,作用是用来保存代码,保存在其内部的代码块 如果Bloc...

  • iOS block基本使用

    block的感觉是越用越喜欢,下面就简单说说她的基本使用,block基本有下面四种情况。 1.无参数无返回值 2....

  • iOS - block基本使用

    block的概念 OC在C的基础之上新增了一些数据类型。 BOOLBoolenclassnilSELidblock...

  • iOS开发 多视角抛析匿名函数—— Block

    一.Block的基本使用1.概念在iOS开发中Block的使用随处可见,使用场景也非常多,例如在网络中进行网络请求...

  • ios block使用

    iOS Block的使用一 .最简单的block使用******使用block的三个步骤:1.定义block变量 ...

  • iOS之block基本使用

    block在iOS日常开放中已经越来越受欢迎了,小结一下,填补之前遇到的坑 block block的作用:是用来保...

网友评论

      本文标题:iOS Block基本使用(一)

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