美文网首页
iOS底层 -- Blcok本质之__Block修饰符

iOS底层 -- Blcok本质之__Block修饰符

作者: happy神悦 | 来源:发表于2020-09-10 09:37 被阅读0次

    一、__Block修饰auto变量

    • __block可以用于解决block内部无法修改auto变量值的问题
    • __block不能修饰全局变量、静态变量(static)

    定义一个__block修饰的auto变量

    Block block;
    __block int age = 10; 
    block = ^{
        age = 20;
        NSLog(@"%d", age);
    };
    block();
    

    编译器会将__block变量包装成一个对象(结构体)

    struct __main_block_impl_0 {
      struct __block_impl impl;
      struct __main_block_desc_0* Desc;
      __Block_byref_age_0 *age; // by ref
      __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_age_0 *_age, int flags=0) : age(_age->__forwarding) {
        impl.isa = &_NSConcreteStackBlock;
        impl.Flags = flags;
        impl.FuncPtr = fp;
        Desc = desc;
      }
    };
    
    struct __Block_byref_age_0 {
     void *__isa;   // isa指针
     __Block_byref_age_0 *__forwarding; // 指向自身的指针
     int __flags;
     int __size; // 结构体的大小
     int age;    // auto变量的值
    };
    

    二、__block内存管理

    1.当block在栈上时,并不会对__block变量产生强引用

    2.当block被拷贝到堆上

    • 会调用block内部的copy函数
    • copy函数内部会调用_Block_object_assign函数
    • _Block_object_assign函数会对__block变量形成强引用(retain)
    static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {
        _Block_object_assign((void*)&dst->objc, (void*)src->objc, 3/*BLOCK_FIELD_IS_OBJECT*/);
    }
    

    3.当block从堆中移除时

    • 会调用block内部的dispose函数
    • dispose函数内部会调用_Block_object_dispose函数
    • _Block_object_dispose函数会自动释放指向的对象(release)
    static void __main_block_dispose_0(struct __main_block_impl_0*src) {
        _Block_object_dispose((void*)src->objc, 3/*BLOCK_FIELD_IS_OBJECT*/);
    }
    

    三、_forwarding指针的作用

    复制之前:
    age(栈区age结构体)->_forwarding(指向自己的指针)->age(age成员变量值)

    复制之后:
    age(栈区age结构体)->_forwarding(指向堆区age结构体)->age(age成员变量值)

    四、__block修饰对象类型

    1.当__block变量在栈上时,不会对指向的对象产生强引用

    2.当__block变量被copy到堆时

    • 会调用__block变量内部的copy函数
    • copy函数内部会调用_Block_object_assign函数
    • _Block_object_assign函数会根据所指向对象的修饰符(__strong、__weak、__unsafe_unretained)做出相应的操作,形成强引用(retain)或者弱引用(注意:这里仅限于ARC时会retain,MRC时不会retain)

    强引用:

    Block block;
    __block Person *person = [[Person alloc] init];
    block = ^{
        NSLog(@"%@", person);
    };
    
    struct __Block_byref_person_0 {
      void *__isa;
      __Block_byref_person_0 *__forwarding;
      int __flags;
      nt __size;
      void (*__Block_byref_id_object_copy)(void*, void*);//从栈上复制到堆上要进行的操作
      void (*__Block_byref_id_object_dispose)(void*);//从堆上移除要进行的操作
      Person *person;//强引用
    };
    

    弱引用:

    Block block;
    Person *person0 = [[Person alloc] init];
    __block __weak Person *person = person0;
    block = ^{
        NSLog(@"%@", person);
    };
    
    struct __Block_byref_person_0 {
      void *__isa;
      __Block_byref_person_0 *__forwarding;
      int __flags;
      int __size;
      void (*__Block_byref_id_object_copy)(void*, void*);//从栈上复制到堆上要进行的操作
      void (*__Block_byref_id_object_dispose)(void*);//从堆上移除要进行的操作
      Person *__weak person;//弱引用
    };
    

    3.当__block变量从堆上移除

    • 会调用__block变量内部的dispose函数
    • dispose函数内部会调用_Block_object_dispose函数
    • _Block_object_dispose函数会自动释放指向的对象(release)

    相关文章

      网友评论

          本文标题:iOS底层 -- Blcok本质之__Block修饰符

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