Block看这一篇就够了

本文详细解析了Block的概念、底层结构、存储区域、变量截获、使用__block修饰符、Block的copy行为以及循环引用问题。通过实例代码转化为C++,深入探讨了Block的工作原理和内存管理,帮助开发者全面掌握Block的使用。
摘要由CSDN通过智能技术生成
1、Block是什么

block是一个封装了函数调用以及函数调用环境的OC对象(内部也有一个isa指针)

2、底层探究

示例代码,在main.m中简单创建一个block,然后转化为C/C++代码,研究其结构、原理

int main(int argc, const char * argv[]) {
    void (^block)(void) =  ^(){
        NSLog(@"block");
    };
    block();
    return 0;
}

打开终端执行xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m,会生成一个main.cpp文件,接下来大部分时间都是研究这个文件。其中blcok 的代码转化为下面代码

通过clang命令行工具中的-rewrite-objc参数,可以把OC代码转化为C++的实现

int main(int argc, const char * argv[]) {
    //blcok创建
    void (*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
    //调用
    ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
    return 0;
}

上面代码的意思就是调用__ main _ block _ impl _ 0()函数,并且给该函数传递__ main _ block _ func_ 0__ main _ block _ desc _ 0_DATA参数,构建blcok,也就是取__ main _ block _ impl _ 0()函数的返回值,赋值给block指针。之后在调用这个block。
上面涉及了三种结构,分别是__ main _ block _ impl _ 0()__ main _ block _ func _ 0__ main _ block_ desc_0_DATA

1)__ main _ block _ impl _ 0()

struct __main_block_impl_0 
{
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  // 构造函数(类似于OC的init方法),返回结构体对象
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) 
  {
    impl.isa = &_NSConcreteStackBlock;//表示block类型
    impl.Flags = flags;
    impl.FuncPtr = fp;//blcok内代码块地址
    Desc = desc;//存储block对象占用内存大小
   }
};

//Block对象结构
struct __block_impl {
	void *isa;
	int Flags;//用于按位表示一些block附加信息
	int Reserved;//保留变量
	void *FuncPtr;//存储了执行 block 代码块的函数地址
};

我们可以看到__ main _ block _ impl _ 0()是一个结构体,__ main _ block _ impl _ 0内部有一个构造函数,在构造函数内部使用FuncPtr记录封装要执行代码的地址(__ main_block_func_0地址),使用Desc记录blcok占用内存大小,除了有构造函数还有两个成员变量,分别是

  • __ block_impl impl:__ block_impl是__ main_block_impl_0结构体的第一个成员,相当于将__ block_impl结构体的成员直接拿出来放在__ main_block_impl_0中,那么也就说明__ block_impl的内存地址就是__main_block_impl_0结构体的内存地址开头,这也是在block调用时,使用成员变量获取FuncPtr的值,来实现函数调用的原因
  • __main_block_desc_0* Desc:方便获取block占用内存大小。

了解了__main_block_impl_0结构之后,我们再来分析一下block的创建。

 void (*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));

block的创建也就是通过参数初始化__ main _ block _ impl _ 0()结构,并且将初始化后的结构体地址赋值给block指针,而参数__ main _ block _ func_ 0记录了block内部代码块的地址,而__ main _ block _ desc _ 0_DATA参数记录了对象的相关信息,例如block对象占用内存的大小。
下面我们分别看看这两个参数

  • __main_block_func_0
// 封装了block执行逻辑的函数
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  NSLog((NSString  *)&__NSConstantStringImpl__var_folders_yl_5wf9qyc526sfkg_phlkp9r2r0000gp_T_main_2f0d21_mi_0);
}

我们可以看到一个NSLog,这正是我们在blcok中写的代码,由此可以总结出我们写在block块中的代码封装到__main_ block_func_0函数内部了,并将__ main_block_func_0函数的地址作为*fp传入了__main_block_impl_0的构造函数中保存在结构体内FuncPtr变量中,也就是FuncPtr指针指向block代码块。

3)__main_block_desc_0_DATA

其结构是__

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员的修养

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值