背景
OC中的block对于iOS开发新入门的同学确实有点难以理解,总结起来其实有两个难点:一是用法,也就是初学者不知道怎么用;二是原理,block究竟是个什么东西,其内部究竟是怎样组织的。针对以上两点,我从先从个人角度讲解一下其用法,然后再将OC代码转换成C语言,了解其内部具体实现。
用法
1、全局定义Block,即在文件最开始定义block的形式,相当于定义一个类型,简单理解为此类型类似于Int等,方式如下:
typedef void(^AddBlock)(int a, int b);
然后:
@property (nonatomic, copy) AddBlock addBlock;
调用方式:
self.addBlock = ^(int a, int b) {
int sum = a + b;
NSLog(@"%d", sum);
};
self.addBlock(3, 5); //输出为8
2、局部定义Block,使用方式如下所示:
void(^reductionBlock)(int a, int b) = ^(int a, int b) {
int result = a - b;
NSLog(@"%d", result);
};
reductionBlock(5,3);
3、Block的属性为什么要用Copy?
Block采用copy方式,实际上是放在堆区里面的,堆区内的空间需要程序员自己去释放,系统不会自动回收,因此不会出现访问坏内存导致的崩溃了。
Block原理
1、首先定义一个main.m文件,内容如下:
#include <stdlib.h>
int main()
{
void(^reductionBlock)(int a, int b) = ^(int a, int b) {
int result = a - b;
};
reductionBlock(5,3);
return 0;
}
2、使用clang -rewrite-objc main.m命令将其转换成main.cpp文件,转换后
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
//改block的初始化方法
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
//Block方法中的具体实现最后转换成了一个静态方法,并将这个方法指针传给结构体,最后相当于调用结构体中的这个function指针。
static void __main_block_func_0(struct __main_block_impl_0 *__cself, int a, int b) {
int result = a - b;
}
static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
int main()
{
void(*reductionBlock)(int a, int b) = ((void (*)(int, int))&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
((void (*)(__block_impl *, int, int))((__block_impl *)reductionBlock)->FuncPtr)((__block_impl *)reductionBlock, 5, 3);
return 0;
}