中介者模式 (自动)
循环引用
self.block=^(void){
};
self.block();
self生命周期: self->block->self
weakSelf
_ _weak typeof(self)weakSelf = self;
加入一层弱引用就可以解决循环引用了吗?
如果在block里异步调用weakSelf,会导致提前释放
_ _weak typeof(self)weakSelf = self;
self.block=^(void){
dispatch();
NSlog(@"%@",weakSelf.age);
};
self.block();
self生命周期:self->block->weakSelf->block
说明:在block区内已经释放,到self.block()调用时已经被释放,所以值为null。
weakSelf不足以保证self的生命周期。
Strong
_ _weak typeof(self)weakSelf = self;
self.block=^(void){
__strong __typeof(weakSelf)strongSelf=weakSelf;
dispatch();
NSlog(@"%@",weakSelf.age);
};
self生命周期:self->block->weakSelf->Strong->weak->self
self在block区间打印完Log后才释放,self在弱引用表里面设置为nil,所以后续self才可以释放。
__block (手动)
__block ViewController *vc = self;
self.block=^void{
dispatch(){
NSLog();
vc=nil;
};
};
self.block();
self生命周期:self->vc->nil->block
原因总结:循环引用的解决方法无非就是解决self和block的通讯。
通讯的方式有很多:传参,协议,代理等等.
传参
typedef void(^Block) (ViewController *);
@property(nonatomic,copy)Block block;
-(void)viewDidload{
self.name=@"Wilbur";
self.block=^(ViewController *vc){
dispatch();
NSLog(@"%@",vc.name);
}
};
self.block();
vc作为参数压栈进block对self不造成持有关系
self生命周期:self->block->_vc
Clang层看block
int main(){
void(*block)(void)=(
&main_block_impl_0(__main_block_func_0,&__main_block_desc_0_DATA)
);
__block_imp(block->FuncPtr(block());
}
static void __main_block_func_0(struct __main_block_impl_0 *__cself){
printf("hello world");
}
##impl_0 的调用func_0
struct __main_block_impl_0{
struct __block_impl impl;
struct __main_block_desc_0 *Desc;
__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;
}
};
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)};
由此可以看出block实际上是一个匿名函数调用的__main_block_impl_0
__block捕获外界变量
如果在外界添加一个变量 int a = 10;
变化
static void __main_block_func_0(struct __main_block_impl_0 *__cself){
int a = __cself->a; //第一层copy
printf("hello world");
}
int main(){
int a = 10;
mian_block_impl_0(func_0,&DATA,a);
}
struct __main_block_impl_0{
int a;
__main_block_impl_0(*fp,*desc,int _a,inf flags):a(_a){
xxx与上诉一样
}
}
可以看到 int a = _cself->a 与 int a=10 指向了同一片内存空间
那么再给__block 引用一个外界变量
__block int a=10;
int main(){
__Block_byref_a_0 a ={
void* 0,
(__Block_byref_a_a *)&a,
0,
sizeof(__Block_byref_a_0),
10};
__main_block_impl_0(func_0,&DATA,&a,570425344);
}
struct __Block_byref_a_0{
void *isa;
__Block_byref_a_0 *__forwarding
int __flags;
int __size;
int a;
};
变量a被封装成了结构体对象
struct __main_block_0{
struct __block_imp impl;
struct __main_block_desc_0 *Desc;
__Block_byref_a_a *a;
__main_block_impl_0(*fp,*desc,__Block_byref_a_0 *_a,flags ):a(a->__forwarding){
impl.isa=&_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __main_block_func_0(struct __main_block_impl_0 *cself){
__Block_byref_a_0 *a = __cself->a;
printf("hello world %d",(a->__forwarding->a))
}
可以看到普通变量a 和 block引用变量a的区别
1.值拷贝/指针拷贝的不同
2.生产的结构体不同,会有isa等等赋值
3.保存相应的原始变量 并赋予*a = __cself->a
4.传递一个地址给block &
Block底层
struct Block_layout{
void *isa
flags
reserve
BlockInvokeFunction invoke
Struct Block_descriptor_1 *descriptor
}
1.block的调用情况
clang层搜索private.block.h或者是bt都可以看到block的调用情况
retainBlock
NSGlobalBlock
NSStackBlock
BlockCopy
void *_Block_copy(const void *arg){
aBlock =(sturct Block_layout *)arg;
1.判断是否需要释放 retun aBlock
2.判断是否是全局block return aBlock
3.else证明这是一个栈的block,第二层复制copy
else{
sturct Block_layout *result = malloc(aBlock->descriptor->size);
memmove(result,aBlock,aBlock->descripotro->size)
#if __has_feature(ptrauch_calls)
//重新标记 invoke的指针作
result->invoke = aBlock->invoke;
#endif
//重新设置refcount
result->flags &= ~(BLOCK_REFCOUNT_MASK|BLOCK_DEALLOCATING);
restule->flags |= BLOCK_NEEDS_FREE |2 //逻辑计数=1
_Block_call_copy_helper(result,aBlock);
//设置最新的isa
result->isa = _NSConcreteMallocBlock;
return result;
}
}
Blockdispose.cold
NSMallocBlock
Block_has_cpoy_dispose (descriptor2)
static struct Block_descriptor_2 * _Block_descriptor_2(struct Block_layout *aBlock){
if (!(aBlock->flags & BLOCK_HAS_COPY_DISPOSE))return NULL;
desc = aBlock->descriptor;
desc = sizeof(struct Block_descriptor_1);
return (descriptor_2 *)desc;
}
Block_has_signature(descriptor3)
static struct Block_descriptor_3 * _Block_descriptor_2(struct Block_layout *aBlock){
if (!(aBlock->flags & BLOCK_HAS_SIGNATURE)) return NULL;
desc = aBlock->descriptor;
desc = sizeof(descriptor1);
if(aBlock->flags & BLOCK_HAS_COPY_DISPOSE){
desc =size(descriptor2)
}
return (struct Block_descriptor_3 *)desc;
}
2.descriptor
descriptor1{
reserve
size
}
descriptor2{
copy
dispose
}
descriptor3{
signature
layout
}
3.block的三层拷贝
static void __main_block_func_0(sturct __main_block_impl_0 *cself){
__Block_byref_a_0 *a=__cself->a;
static void __main_block_copy_0(struct __main_block_impl_0 *dst,struct __main_block_impl_0 *src){
_Block_object_assign(&dst->a,src->a,8)
}
static void __main_block_copy_0(struct __main_block_impl_0 *dst)
{
_Block_object_dispose(src->a,8)
}
_Blcok_object_assign
void _Block_object_assign(void *destArg,const void *object ,const int flags){
**dest=destArg //二级指针拷贝
switch(os_assumes(flags&BLOCK_ALL_COPY_DISPOSE_FLAGS)){
case BLOCK_FIELE_IS_OBJECT: //判断是否是普通对象类型
_Block_retain_object(object);
*dest = object //
case BLOCK_FIELE_IS_BLOCK: //判断是否是block变量
*dest = _Block_copy(object);
case BLOCK_FIELD_IS_BYREF | BLOCK_FIELD_IS_WEAK: //判断是否是__block修饰的变量 或者 weak修饰
case BLOCK_FIELE_IS_BYREF: //判断是否是__block修饰的变量
*dest = _Block_byref_copy(object)
}
}
_block_byref_copy
_block_byref_copy(*arg){
struct Block_byref *src = (struct Block_byref *) arg;三层拷贝
struct Block_byref *copy = (struct Block_byref*)malloc(src->size)
copy->isa=NULL;
copy->flags = src->flags
copy->forwarding = copy;//patch heap copy to point to itself
src->forwarding = copy;//patch stack to point to heap
从堆->栈的拷贝
copy->size = src->size
}
自从说明了__block从底层来看,为什么能够捕获外界变量的原因就在这
block三层拷贝
第一层:int a = __cself->a; //第一层值copy
第二层:指针拷贝
第三层:堆栈拷贝
copy->size = src->size