标签:
一.block的内存分析
如上图:
定义了一个weak的block,那么它在内存中的表现形式如右下角,
1.没有对block进行copy操作,而是weak,block就存储在栈空间中.
2.如果block存储于栈空间,不会对block内部所用到的对象产生强引用.
如上图:
对block进行了一次copy操作,如果对block进行copy操作,block就会存储到堆空间当中.
1.如果block存储于堆空间,就会对block内部所用到的对象产生强引用.
2.如下图所示,就会产生循环引用,造成P对象无所释放,引发内存泄露
二.block的循环引用
解决办法为:
XqPersion *p = [XqPersion alloc] init];
__weak typeof(p) weakP = p;
或者用__unsafe_unretained typeof(p) weakP = p;
p.myBlock = ^{
[p run];
}
而对于非ARC的解决办法为:
XqPersion *p = [XqPersion alloc] init];
__block typeof(p) weakP = p;
p.myBlock = ^{
[p run];
}
[p release];
三.block的变量访问
1.
int age =10;
void (^block)() = ^{
NSLOG(@"age = %d",age);
}
age = 20;
block();
输出结果为:10
void (^block)() = ^{
NSLOG(@"age = %d",age);
}在声明这个block代码的时候,它已经把10放到了NSLOG(@"age = %d",10);以后这个地方就是一个常量10,可以称它为值捕获;
表面上看起来是age变量,但实际上它是把age的值10放进去了
相当于
void (^block)() = ^{
NSLOG(@"age = %d",10);
}
无age的值怎么改变, block输出的都是10
2.
__block int age =10;
void (^block)() = ^{
NSLOG(@"age = %d",age);
}
age = 20;
block();
输出结果:20
当在前面声明__block时候,实际上传递的是age的地址 &age
在编译的时候block为:
void (^block)() = ^{
NSLOG(@"age = %d",*(&age));
}
所有当下面age的值发生改变的时候 输出的block也相应发生改变;
三.block的数据结构定义
一个block实例实际上由6部分组成:
struct Block _layout{
void *isa;
int flags;
int reserved;
void (*invoke)(void *,...);
struct Block descriptor *descriptor;
};
1,isa指针,所有的对象都有该指针,用于实现对象相关的功能
2,flags,用于按bit位表示一些block的附加信息
3.reserved,保留变量
4.invoke,函数指针,指向具体的block实现的函数调用.
5.descriptor, 表示该block的附加描述信息
6.variables, capture过来的变量,block能够访问它外部的局部变量,就是因为将这些变量(或变量地址)复制到了结构体中.
在Object-C一共有3种类型的block
1,_NSConcreteGlobalBlock,全局的静态Block,不会访问任何的外部变量
2,_NSConcreteStackBlock,保存在栈中的Block,当函数返回时会被销毁
3,_NSConcreteMallocBlock,保存在堆中的Block,当引用计数器为0时会自动销毁
标签:
原文地址:http://www.cnblogs.com/xqios/p/4286504.html