美文网首页iOS进阶
06.4-OC中block捕获对象类型的变量

06.4-OC中block捕获对象类型的变量

作者: 光强_上海 | 来源:发表于2020-06-14 22:46 被阅读0次

block捕获对象类型的变量

前面讲解的block变量捕获,我们讲解了block捕获基本数据类型的情况,下面我们再来分析下捕获对象类型的auto变量,分析下block的底层内存布局情况,我们创建一个新工程,创建一个Person类,代码如下:

Person类:

@interface Person : NSObject

@property (nonatomic, assign) int age;
@end


@implementation Person

- (void)dealloc {
    NSLog(@"%s",__func__);
}
@end

main函数:

typedef void(^MyBlock)(void);

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        
        MyBlock block;
        
        {
            // person默认是__strong修饰符修饰的
            __strong Person *person = [[Person alloc] init];
            person.age = 10;
            
//            __weak typeof(Person) *weakP = person;
            
            // block变量强引用着^{},编译器就会进行`copy`操作,将这个block从栈拷贝到堆上
            block = ^{
                NSLog(@"-%d", person.age);
            };
        }
       
        // 执行block,上面的person对象已经出了函数作用域,但是还没有释放
        block();
    }
    return 0;
}

我们执行命令xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 main.mmain.m文件转换为c++文件,转换后代码如下:

main:函数

int main(int argc, const char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
        
        MyBlock block;
        {
            Person *person = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("alloc")), sel_registerName("init"));
            
            ((void (*)(id, SEL, int))(void *)objc_msgSend)((id)person, sel_registerName("setAge:"), 10);

            block = &__main_block_impl_0(
                                         __main_block_func_0,
                                         &__main_block_desc_0_DATA,
                                         person,
                                         570425344
                                         );
        }
        
        // 执行block
        block->FuncPtr(block);
    }
    return 0;
}

block结构体:

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
    
  // 在block结构体内部,person对象是强指针引用还是弱指针引用,取决于block内部访问的auto变量是__strong修饰还是__weak修饰的
  Person *__strong person;
    
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, Person *__strong _person, int flags=0) : person(_person) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

__main_block_desc_0:结构体:

static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
    
    // 只有在block内部访问了auto对象类型的变量时,才会有`copy`和`dispose`函数指针存在,因为只有访问的是对象类型才需要进行内存管理相关操作
    
    // copy函数指针,指向__main_block_copy_0函数
  void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
  
    // dispose函数指针,指向__main_block_dispose_0函数
  void (*dispose)(struct __main_block_impl_0*);
}

__main_block_copy_0函数:

// 当block调用copy操作,将block从栈拷贝到堆上时,就会调用此函数
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {
    /**
    _Block_object_assign:负责内存管理相关操作,也就是说这个函数会根据block结构体内部捕获的变量的引用类型进行内存管理:
     1.如果block结构体内捕获的变量是__strong类型的指针,那么这个指针就对block外面的对象进行强引用,进行retain操作,引用计数器+1
     2.如果block结构体内捕获的变量是__weak类型的指针,那么这个指针就对block外面的对象进行弱引用
     */
    _Block_object_assign(
                         (void*)&dst->person,
                         (void*)src->person,
                         3/*BLOCK_FIELD_IS_OBJECT*/
                         );
}

__main_block_dispose_0函数:

// 当堆中的block需要销毁时,会调用此函数
static void __main_block_dispose_0(struct __main_block_impl_0*src) {
    // block结构体内的强指针断开对外部auto变量的强引用时,进行release操作,引用计数器-1
    _Block_object_dispose(
                          (void*)src->person,
                          3/*BLOCK_FIELD_IS_OBJECT*/
                          );
}

block捕获对象类型auto变量底层结构分析总结如图:

image

讲解示例代码Demo地址:https://github.com/guangqiang-liu/06.4-BlockDemo

更多文章

相关文章

  • 06.4-OC中block捕获对象类型的变量

    block捕获对象类型的变量 前面讲解的block变量捕获,我们讲解了block捕获基本数据类型的情况,下面我们再...

  • iOS原理篇(五):Block探究

    Block原理 Block变量捕获 Block类型 copy操作和Block内部访问对象类型的变量 __block...

  • iOS中的Block详解2(附面试题) - 底层原理总结

    block对对象变量的捕获 block一般使用过程中都是对对象变量的捕获,那么对象变量的捕获和基本数据类型变量相同...

  • oc中block底层原理分析(二)

    一、block对对象变量的捕获 block一般使用过程中都是对对象变量的捕获,那么对象变量的捕获同基本数据类型变量...

  • block的本质2

    1. block对对象变量的捕获 block一般使用过程中都是对对象变量的捕获,那么对象变量的捕获同基本数据类型变...

  • block-对象类型的auto变量

    从上些章节block-变量的捕获(caputer)中,详细说了基本类型的auto变量的捕获,现在来了解下,对象类型...

  • block底层原理探究(二):内存管理

    前篇block底层原理探究(一):捕获,我们探究了block捕获外部变量的原理;如果block捕获的是对象类型的a...

  • block使用及其底层原理

    一 block基本使用 二 block底层结构 三 block变量捕获 四 block的类型 五 block对象类...

  • Block 第三次学习 感谢 MJ老师

    block 内部结构 Block block 变量捕获 变量类型捕获到block 内部访问方式局部变量auto(平...

  • Block

    1. Block中UIlable 和 int 变量分别是怎么捕获? 对于基本类型的局部变量截获其值 对于对象类型的...

网友评论

    本文标题:06.4-OC中block捕获对象类型的变量

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