您的位置:首页 > 移动开发 > Objective-C

objective c下的block模型

2016-01-05 15:14 495 查看

前言

通过clang将objective c代码翻译成cpp代码,阅读代码的实现去理解objc中block模型。

objective c代码

#import <Foundation/Foundation.h>
void foo_()
{
int i = 2;
NSNumber *num = @3;

long (^myBlock)(void) = ^long() {
return i * num.intValue;
};

long r = myBlock();
}


clang翻译objective c代码块

clang -rewrite-objc block.m


Objective c的block模型

首先我们简化一下cpp代码,大致如下:

struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};

static struct __foo__block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __foo__block_impl_0*, struct __foo__block_impl_0*);
void (*dispose)(struct __foo__block_impl_0*);
} __foo__block_desc_0_DATA = { 0, sizeof(struct __foo__block_impl_0), __foo__block_copy_0, __foo__block_dispose_0};

struct __foo__block_impl_0 {
struct __block_impl impl;
struct __foo__block_desc_0* Desc;
int i;
NSNumber *num;
__foo__block_impl_0(void *fp, struct __foo__block_desc_0 *desc, int _i, NSNumber *_num, int flags=0) : i(_i), num(_num) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};

static long __foo__block_func_0(struct __foo__block_impl_0 *__cself) {
int i = __cself->i; // bound by copy
NSNumber *num = __cself->num; // bound by copy

return i * ((int (*)(id, SEL))(void *)objc_msgSend)((id)num, sel_registerName("intValue"));
}

void foo_(){
int i = 2;
NSNumber *num = ((NSNumber *(*)(id, SEL, int))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithInt:"), 3);

long (*myBlock)(void) = ( (long (*)()) & __foo__block_impl_0((void *)__foo__block_func_0, &__foo__block_desc_0_DATA, i, num, 570425344));

long r = ( (long (*)(__block_impl *)) ((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock);
}


myBlock对象:在转换过后被转换为结构体struct __foo__block_impl_0,而struct __foo__block_impl_0结构体中含有isa指针,实际上它是一个对象,说明block其实是一个对象,有不同的存储形式,而在struct __foo__block_impl_0中有一句:impl.isa = &_NSConcreteStackBlock; 说明上述代码中myBlock对象实际上是存储在stack上的对象。

foo_函数: 在转换过后形成静态函数static long __foo__block_func_0,函数的参数正是myBlock对象,在long __foo__block_func_0函数中直接操作myBlock对象的属性。

如果我们在myBlcok中修改i或者num的值,编译器会提示警告,通过struct __foo__block_impl_0的狗仔函数__foo__block_impl_0(void *fp, struct __foo__block_desc_0 *desc, int _i, NSNumber *_num, int flags=0) : i(_i), num(_num),可以看出实际上
4000
i和num值实际上赋值给了myBlock对象,所以在myBlock里面修改i或者num的值,修改的是block的成员变量,而不是通过参数传递进来的i,num,实际上就是c语法中的传递值和指针的区别。

这么说如果我们想修改i的值,参数传递指针就可以了嘛,说的没错,继续往下看你。

在block中如果我们想要修改 block外的值,只需要在值申明之前加上__block关键字即可。

下面接着分析含有__block变量的block模型

objective c代码

#import <Foundation/Foundation.h>
void foo_(){
__block int i = 2;
NSNumber *num = @3;

long (^myBlock)(void) = ^long() {
return i * num.intValue;
};
long r = myBlock();
}


clang翻译objective c代码块

clang -rewrite-objc block2.m


Objective c的block模型

struct __Block_byref_i_0 {
void *__isa;
__Block_byref_i_0 *__forwarding;
int __flags;
int __size;
int i;
};

struct __foo__block_impl_0 {
struct __block_impl impl;
struct __foo__block_desc_0* Desc;
NSNumber *num;
__Block_byref_i_0 *i; // by ref
__foo__block_impl_0(void *fp, struct __foo__block_desc_0 *desc, NSNumber *_num, __Block_byref_i_0 *_i, int flags=0) : num(_num), i(_i->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};

struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};

static long __foo__block_func_0(struct __foo__block_impl_0 *__cself) {
__Block_byref_i_0 *i = __cself->i; // bound by ref
NSNumber *num = __cself->num; // bound by copy

return (i->__forwarding->i) * ((int (*)(id, SEL))(void *)objc_msgSend)((id)num, sel_registerName("intValue"));
}

void foo_(){
__attribute__((__blocks__(byref))) __Block_byref_i_0 i = {(void*)0,(__Block_byref_i_0 *)&i, 0, sizeof(__Block_byref_i_0), 2};
NSNumber *num = ((NSNumber *(*)(id, SEL, int))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithInt:"), 3);

long (*myBlock)(void) = ((long (*)())&__foo__block_impl_0((void *)__foo__block_func_0, &__foo__block_desc_0_DATA, num, (__Block_byref_i_0 *)&i, 570425344));

long r = ((long (*)(__block_impl *))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock);
}


myBlock对象:在转换过后被转换为结构体struct __foo__block_impl_0,不同于前面,多了一个__Block_byref_i_0的结构体,用来保存i的值

这里多了一个__Block_byref_i_0的结构体,而__Block_byref_i_0的结构体实际上也是一个对象,含有isa指针,在__foo__block_impl_0的构造函数中传递的是__Block_byref_i_0的指针,这样我们就可以直接在myBlock中对i的值进行修改,正如我们前面提到的指针传递。

希望通过本文,可以加深你对objective c的block模型的理解,如有错误,请提出,我会及时改正,大家共同学习。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: