Block对象研究

2016-06-14  本文已影响24人  zhouluyao

研究工具:clang

创建一个名为block.c的源文件

#include <stdio.h>

int main(){

^{printf("Hello ,World!\n");}();

return 0;

}

命令行输入:clang  -rewrite-objc block.c   可在block.c所在的目录下看到一个block.cpp文件进行分析

block的主要构成

isa指针:所有对象都有该指针,用于实现对象的相关功能

invoke:函数指针,指向具体的block实现的函数指针

descriptor:标示该block的附加信息,主要是size大小,以及copy和dispose函数的指针

variables:block能够访问它外部的局部变量,就是因为这些变量(或者变量的地址)复制到了结构体中

结构体本身并不附带任何额外信息

创建block时,实际就是在方法中声明一个struct,并且初始化该struct的成员。而执行block时,就是调用那个单独的C函数,并把该struct指针传递过去。

在objc中,根据对象的定义,凡是首地址是*isa的结构体指针,都可以认为是对象(id).

常见的3种类型的block

_NSConcreteGlobalBlock,全局静态block,不会访问任何外部变量

_NSConcreteStackBlock,保存在栈中的block,block返回时被销毁

_NSConcreteMallocBlock,保存在堆中的block,引用计数为0时被销毁

只有一个block被调用copy方法的时候,系统才会将这个block复制到堆上,从而产生NSConcreteMallocBlock类型的block

局部变量在block内不能被修改

static void__main_block_func_0(struct__main_block_impl_0 *__cself) {

inti = __cself->i;// bound by copy

printf("%d",i);}

在block中引用的局部变量i,实际上是在声明block时,被复制到__main_block_impl_0结构体的那个变量,block内部修改变量i,不会影响到外部的变量i.

__block修改局部变量

struct__Block_byref_i_0 {

void*__isa;  //凡是首地址是*isa的结构体指针,都可以认为是对象(id).

__Block_byref_i_0 *__forwarding;

int __flags;

int __size;

int i;}

变量i,成了一个结构体 在__main_block_impl_0 中引用着__Block_byref_i_0 *i;// by ref 结构体指针 ,这样就起到修改外部局部变量的作用

负责结构体__Block_byref_i_0的内存管理,增加了copy和dispose函数指针,用于在调用前后修改相应变量的引用计数

static struct__main_block_desc_0 {

size_t reserved;

size_t Block_size;

void(*copy)(struct__main_block_impl_0*,struct__main_block_impl_0*);

void(*dispose)(struct__main_block_impl_0*);

} __main_block_desc_0_DATA = {0,sizeof(struct__main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};

ARC对block类型的影响

int main(int argc,char* argv[]) {

@autoreleasepool{

int i =1024;

void(^block)(void) = ^{

printf("%d",i);

};

block();

NSLog(@"%@",block);

return0;}

}

非ARC运行结果//10242016-06-14 10:46:03.238 MemoryInMRC[7473:3171916] <__NSStackBlock__: 0x7fff5a58f548>

ARC运行结果//10242016-06-14 10:49:03.121 MemoryInMRC[7528:3174176] <__NSMallocBlock__: 0x7fe36a7003e0>

循环引用

self对block引用,block捕捉到self时

XYZBlockKeeper*__weakweakSelf=self;  self.block=^{   [weakSelf doSomething];//捕获到的是弱引用  }

如果捕获到的是当前对象的成员变量对象,同样也会造成对self的引用

id  tmpIvar=_ivar;//临时变量,避免了self引用   self.block=^{   [tmpIvar msg];  }

block对变量的捕获规则

静态储存区变量:全局变量、static修饰变量可以修改

block接受的参数,可以修改

__block引用,可以修改。//bound by reference 如果时id类型则不会被block retain,必须手动处理其内存管理。

局部变量不可以修改//bound by copy

上一篇 下一篇

猜你喜欢

热点阅读