block的实现原理

block的实现原理

将代码在Xcode中编写后,编译查看结果,test3和test4的结果我想大家都能猜到,基本C语言的一致.
但test1和test2的实现原理是比较重要的,运行后对结果的怎么实现的无法理解.
代码如下:

void test1() {
	int a = 8;
	void (^myBlock)() = ^{
		NSLog(@"a = %d",a);
	};
	a = 12;
	myBlock();
}

void test2() {
	__block int a = 8;
	void (^myBlock)() = ^{
		NSLog(@"a = %d",a);
	};
	a = 12;
	myBlock();
}

void test3() {
	static int a = 8;
	void (^myBlock)() = ^{
		NSLog(@"a = %d",a);
	};
	a = 12;
	myBlock();
}

int a = 8;
void test4() {
	
	void (^myBlock)() = ^{
		NSLog(@"a = %d",a);
	};
	a = 12;
	myBlock();
}

int main(int argc, const char * argv[]) {
	test4();
	return 0;
}
想要理解block的内部实现原理,我们需要将代码编译成cpp文件.在terminal中以clang -rewrite-objc main.m 指令将其编译生成 main.cpp文件,以下代码是截取重要部分的内容.

--------------------------------------------------------------------------    美丽的分割线  cpp分析部分 ---------------------------------------------------------------

//main函数

int main(int argc, const char * argv[]) {
	test1();
	return 0;
}

//block的实现部分

//1.从这里开始

重点:

//1.1.a的值被初始化成8
//1.2.被传入myBlock的是a,因此被传入的是a的值8.
//1.3由于传入的是8常量,因此在block中不能给a重新赋值.
//1.4block中传入3个参数,
//1.5注意此时a的值8已传入block中,此时可以理解为:block实现部分已经就绪,只欠西北风了</span>
//1.6重新给a赋值12,这个结赋值不会影响block中的a的值,因为block的参数已经传入了,更新后不会再传入
//1.7执行block代码

void test1() {
//1.1
 int a = 8;
//1.2
//1.3
//1.4
//1.5
 void (*myBlock)() = (void (*)())&__test1_block_impl_0((void *)__test1_block_func_0, &__test1_block_desc_0_DATA, a);
//1.6
 a = 12;
//1.7
 ((void (*)(__block_impl *))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock);
}

//2.原先a的值以形参_a的形式传进来,并赋给a,因此block中的a的值为8
    /**
     *  __test1_block_impl_0的实现部分
     *
     *  @param fp       函数指针
     *  @param desc  结构体__test1_block_impl_0的字节长度
     *  @param _a     形参a
     *  @param flags 忽视它
     *
     */

struct __test1_block_impl_0 {
	struct __block_impl impl;
	struct __test1_block_desc_0* Desc;
	int a;
	
	__test1_block_impl_0(void *fp, struct __test1_block_desc_0 *desc, int _a, int flags=0) : a(_a) {
		impl.isa = &_NSConcreteStackBlock;
		impl.Flags = flags;
		impl.FuncPtr = fp;
		Desc = desc;
	}
};

/**
 *  block函数内部功能
 *
 *  @param __cself 结构体的内部变量的引用
 */

//将__test1_block_impl_0中的a的值传给局部变量a中,将会打印该a的值.

static void __test1_block_func_0(struct __test1_block_impl_0 *__cself) {
	int a = __cself->a; // bound by copy
	
	NSLog((NSString *)&__NSConstantStringImpl__var_folders_16_2nnq6r3n5sq_4ynmhpf31szm0000gp_T_main_d05376_mi_0,a);
}

//内部两个参数,第一个为保留,第二个为block的字节长度,通过sizeof(struct __test1_block_impl_0)得到值
static struct __test1_block_desc_0 {
	size_t reserved;
	size_t Block_size;
} __test1_block_desc_0_DATA = { 0, sizeof(struct __test1_block_impl_0)};

//这是block的结构,是个结构体,记住block是个结构体

struct __Block_byref_a_0 {
	void *__isa;
	__Block_byref_a_0 *__forwarding;
 int __flags;
 int __size;
 int a;
};

--------------------------------------------------------------------------    美丽的分割线   test2分析---------------------------------------------------------------

//================ test2 =================================================================
struct __test2_block_impl_0 {
	struct __block_impl impl;
	struct __test2_block_desc_0* Desc;
	__Block_byref_a_0 *a; // by ref
	__test2_block_impl_0(void *fp, struct __test2_block_desc_0 *desc, __Block_byref_a_0 *_a, int flags=0) : a(_a->__forwarding) {
		impl.isa = &_NSConcreteStackBlock;
		impl.Flags = flags;
		impl.FuncPtr = fp;
		Desc = desc;
	}
};
static void __test2_block_func_0(struct __test2_block_impl_0 *__cself) {
	__Block_byref_a_0 *a = __cself->a; // bound by ref
	
	NSLog((NSString *)&__NSConstantStringImpl__var_folders_16_2nnq6r3n5sq_4ynmhpf31szm0000gp_T_main_d05376_mi_1,(a->__forwarding->a));
}
static void __test2_block_copy_0(struct __test2_block_impl_0*dst, struct __test2_block_impl_0*src) {_Block_object_assign((void*)&dst->a, (void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);}

static void __test2_block_dispose_0(struct __test2_block_impl_0*src) {_Block_object_dispose((void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);}

static struct __test2_block_desc_0 {
	size_t reserved;
	size_t Block_size;
	void (*copy)(struct __test2_block_impl_0*, struct __test2_block_impl_0*);
	void (*dispose)(struct __test2_block_impl_0*);
} __test2_block_desc_0_DATA = { 0, sizeof(struct __test2_block_impl_0), __test2_block_copy_0, __test2_block_dispose_0};

void test2() {
 __attribute__((__blocks__(byref))) __Block_byref_a_0 a = {(void*)0,(__Block_byref_a_0 *)&a, 0, sizeof(__Block_byref_a_0), 8};
} 

/**
  *  test2与test1的区别在于此,将block中传入的不是a的值,而是a的地址
  *
  *  @param myBlock 函数名
  *  因此在block中可以重新对a进行赋值
  */

void (*myBlock)() = (void (*)())&__test2_block_impl_0((void *)__test2_block_func_0, &__test2_block_desc_0_DATA, (__Block_byref_a_0 *)&a, 570425344);
 (a.__forwarding->a) = 12;
 ((void (*)(__block_impl *))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock);
}

只分析了test1和test2,我想test3和test4比较好理解.

--------------------------------------------------------------------------    美丽的分割线   test3和test4 cpp代码,自行分析---------------------------------------------------------------

/================ test3 =================================================================
struct __test3_block_impl_0 {
	struct __block_impl impl;
	struct __test3_block_desc_0* Desc;
	int *a;
	__test3_block_impl_0(void *fp, struct __test3_block_desc_0 *desc, int *_a, int flags=0) : a(_a) {
		impl.isa = &_NSConcreteStackBlock;
		impl.Flags = flags;
		impl.FuncPtr = fp;
		Desc = desc;
	}
};
static void __test3_block_func_0(struct __test3_block_impl_0 *__cself) {
	int *a = __cself->a; // bound by copy
	
	NSLog((NSString *)&__NSConstantStringImpl__var_folders_16_2nnq6r3n5sq_4ynmhpf31szm0000gp_T_main_d05376_mi_2,(*a));
}

static struct __test3_block_desc_0 {
	size_t reserved;
	size_t Block_size;
} __test3_block_desc_0_DATA = { 0, sizeof(struct __test3_block_impl_0)};
void test3() {
 static int a = 8;
 void (*myBlock)() = (void (*)())&__test3_block_impl_0((void *)__test3_block_func_0, &__test3_block_desc_0_DATA, &a);
 a = 12;
 ((void (*)(__block_impl *))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock);
}

//================ test4 =================================================================
int a = 8;
struct __test4_block_impl_0 {
	struct __block_impl impl;
	struct __test4_block_desc_0* Desc;
	__test4_block_impl_0(void *fp, struct __test4_block_desc_0 *desc, int flags=0) {
		impl.isa = &_NSConcreteStackBlock;
		impl.Flags = flags;
		impl.FuncPtr = fp;
		Desc = desc;
	}
};
static void __test4_block_func_0(struct __test4_block_impl_0 *__cself) {
	
	NSLog((NSString *)&__NSConstantStringImpl__var_folders_16_2nnq6r3n5sq_4ynmhpf31szm0000gp_T_main_d05376_mi_3,a);
}

static struct __test4_block_desc_0 {
	size_t reserved;
	size_t Block_size;
} __test4_block_desc_0_DATA = { 0, sizeof(struct __test4_block_impl_0)};
void test4() {
	
 void (*myBlock)() = (void (*)())&__test4_block_impl_0((void *)__test4_block_func_0, &__test4_block_desc_0_DATA);
 a = 12;
 ((void (*)(__block_impl *))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock);
}

test3是由static声明,test4是全局变量,因此内从中只有一份.

---end


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值