重新回顾了一下iOS内存管理一书的Block部分,为了加深一下自己对block的理解,这里将其实现总结到这篇博客。
#import "DemoClass.h"
@interface DemoClass()
@end
@implementation DemoClass
-(void)demoFunction{
int a = 10;
void(^testBlock)(void) = ^{
NSLog(@"%i",a);
};
testBlock();
}
@end
cd到DemoClass.m所在的文件夹,然后使用前面提及的命令可以得到如下代码(使用命令后会生成一个DemoClass.cpp文件,拖到最后可看到):
struct __DemoClass__demoFunction_block_impl_0 {
struct __block_impl impl;
struct __DemoClass__demoFunction_block_desc_0* Desc;
int a;
__DemoClass__demoFunction_block_impl_0(void *fp, struct __DemoClass__demoFunction_block_desc_0 *desc, int _a, int flags=0) : a(_a) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __DemoClass__demoFunction_block_func_0(struct __DemoClass__demoFunction_block_impl_0 *__cself) {
int a = __cself->a; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_w4_98ssf10122ddt716rmjjy0vw0000gn_T_DemoClass_cde937_mi_0,a);
}
static struct __DemoClass__demoFunction_block_desc_0 {
size_t reserved;
size_t Block_size;
} __DemoClass__demoFunction_block_desc_0_DATA = { 0, sizeof(struct __DemoClass__demoFunction_block_impl_0)};
static void _I_DemoClass_demoFunction(DemoClass * self, SEL _cmd) {
int a = 10;
void(*testBlock)(void) = ((void (*)())&__DemoClass__demoFunction_block_impl_0((void *)__DemoClass__demoFunction_block_func_0, &__DemoClass__demoFunction_block_desc_0_DATA, a));
((void (*)(__block_impl *))((__block_impl *)testBlock)->FuncPtr)((__block_impl *)testBlock);
}
// @end
感觉还挺长的。。。。,不扯这些没用的,直接进入分析(如果觉得看不习惯c的命名方式,可以将它们用自己习惯的方式重新书写),很明显OC中的demoFunction方法对应的就是static void _I_DemoClass_demoFunction(DemoClass * self, SEL _cmd) ,在demoFunction中定义了一个testBlock闭包对应过来就是这一行代码(以下使用testBlock闭包表示OC中的代码,testBlock变量表示C++代码)
void(*testBlock)(void) = ((void (*)())&__DemoClass__demoFunction_block_impl_0((void *)__DemoClass__demoFunction_block_func_0, &__DemoClass__demoFunction_block_desc_0_DATA, a));
这句话比较简单粗暴,就是把__DemoClass__demoFunction_block_impl_0初始化方法生成的结构体地址复制给testBlock这个函数变量。既然如此我们就转到代码
struct __DemoClass__demoFunction_block_impl_0 {
struct __block_impl impl;
struct __DemoClass__demoFunction_block_desc_0* Desc;
int a;
__DemoClass__demoFunction_block_impl_0(void *fp, struct __DemoClass__demoFunction_block_desc_0 *desc, int _a, int flags=0) : a(_a) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
这是一个结构体__DemoClass__demoFunction_block_impl_0,它包含了构造方法,这个构造方法需要传入两个指针,加上一个int类型变量a,flags有缺省值。这里的a其实就是OC中block捕获的局部变量a。至于另外两个指针,第一个指针就是这一段代码的地址
static void __DemoClass__demoFunction_block_func_0(struct __DemoClass__demoFunction_block_impl_0 *__cself) {
int a = __cself->a; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_w4_98ssf10122ddt716rmjjy0vw0000gn_T_DemoClass_ace8b6_mi_0,a);
}
里面有一个NSLog函数,很明显就是testBlock闭包的代码实现部分,第二个指针就是定义好了的变量__DemoClass__demoFunction_block_desc_0_DATA地址,也就是说声明testBlock闭包的时候系统构造了一个testBlock指针,这个指针指向一个__DemoClass__demoFunction_block_impl_0的结构体,这个结构体里面存储了testBlock闭包的实现以及捕获到的临时变量和相关描述。
block的调用对应的代码如下:
((void (*)(__block_impl *))((__block_impl *)testBlock)->FuncPtr)((__block_impl *)testBlock);
当调用testBlock闭包的时候testBlock指针强转成__block_impl指针(testBlock指针实际上是__DemoClass__demoFunction_block_impl_0指针,由于__block_impl结构体是该结构体的第一个成员所以他们的首地址是一样的因此可以强行转换),然后通过FuncPtr获得testBlock这个闭包的实现,然后传入testBlock指针(主要是为了获取testBlock闭包捕获到的变量的值)。从而完成函数调用。
看着其实还是挺简单的。。。。。。
OC中的闭包实际上对应着结构体__block_impl,由于这个结构体包含了isa指针因此可以相信的是闭包就是一个类,当你定义一个闭包的时候系统生成一个结构体,该结构体中包含了闭包的实现地址以及捕获的变量,需要调用闭包的时候,调用结构体中实现地址中的实现来完成调用。而且可以从实现中看到一个很关键的点,在OC中的局部变量a,是通过值传递的方式传递到结构体的,因此闭包中一般是无法修改捕获的局部变量的。
顺便提一下OC中class和object的结构体:
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;
const char *name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;
struct objc_method_list **methodLists OBJC2_UNAVAILABLE;
struct objc_cache *cache OBJC2_UNAVAILABLE;
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
typedef struct objc_class *Class;
/// Represents an instance of a class.
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
/// A pointer to an instance of a class.
typedef struct objc_object *id;