betway必威IOS 看懂此文,你的block再为非欲WeakSelf弱引用了!IOS 看懂此文,你的block再为未需要WeakSelf弱引用了!

betway必威IOS 看懂此文,你的block再为非欲WeakSelf弱引用了!IOS 看懂此文,你的block再为未需要WeakSelf弱引用了!

前言:

近日都于折腾 Sagit 架框的内存释放的题材,所以针对当时等同片有来心得。

对新手,学到的篇章还以让君用:typeof(self) __weak weakSelf = self。

对于老手,可能早习惯了四处了WeakSelf了。

这次,就来读,如何不用WeakSelf。

前言:

近来还于折腾 Sagit 架框的内存释放的问题,所以针对当时等同块来若干心得。

对新手,学到的篇章还当叫君用:typeof(self) __weak weakSelf = self。

对于老手,可能早习惯了大街小巷了WeakSelf了。

这次,就来学习,如何不用WeakSelf。

1:从引用计数器开始:

此间先规划一个TableBlock类:

@interface BlockTable : NSObject

typedef void (^AddCellBlock)();
@property (nonatomic,copy)AddCellBlock addCell;@end

优先这么简单,一个BlockTable只发生一个block属性,然后输出一段子释放的日志。

-(void)dealloc
{
    NSLog(@"Table relase");//relase为错误字,为了和下图保持一致的错别字,这里就不改了。
}

进而,随意摸一个地方写写代码:来new了一个BlockTable,并打印一下消息:

betway必威 1

这时候它的援数是1,并且有了Table relase 。

跟着给addCell属性赋一个价,并运行:

betway必威 2

一个缺损的波,里面连无引用到table,所以引用数还是1。

1:从引用计数器开始:

此间先规划一个TableBlock类:

@interface BlockTable : NSObject

typedef void (^AddCellBlock)();
@property (nonatomic,copy)AddCellBlock addCell;@end

优先这样简单,一个BlockTable只发一个block属性,然后输出一段落释放的日志。

-(void)dealloc
{
    NSLog(@"Table relase");//relase为错误字,为了和下图保持一致的错别字,这里就不改了。
}

跟着,随意找一个地方写写代码:来new了一个BlockTable,并打印一下音:

betway必威 3

这儿它的援数是1,并且发生了Table relase 。

随着吃addCell属性赋一个值,并运行:

betway必威 4

一个拖欠的风波,里面连没有引用到table,所以引用数还是1。

2:开始循环引用

在block引用table,让她发出循环引用,并运行:

betway必威 5

2:开始循环引用

以block引用table,让她来循环引用,并运行:

betway必威 6

咱们看:引用数成为了3,没有出口对象释放信息了,为甚非是2啊?大大的问号!!

一个属性赋值,为什么增强两独援计数?

咱视:引用数成为了3,没有出口对象释放信息了,为底不是2也?大大的问号!!

一个特性赋值,为什么增强两个援计数?

3:猜解跳跃的计数器

对接下去,把性能设置也nil,运行看:

betway必威 7

设置为nil,还有2?

否正常释放了?

以印证自己对之看起便异常显的猜测:重写addCell的setter方法,不进行其他保存:

@implementation BlockTable
-(void)setAddCell:(AddCellBlock)addCell
{

}

并且失去掉置为nil的代码:再运行看:

betway必威 8

计数器仍为2,而且为释放了。

经过构思,出来了以下的结论:

1:块的定义本身,就会造成1次引用,不过这次引用,在块离开所在的函数时,释放时,抵消掉引用数。

2:存档块的时候,会造成1次引用,而这个引用,是内存无法释放的原因。

3:猜解跳跃的计数器

紧接下去,把性能设置也nil,运行看:

betway必威 9

设置为nil,还有2?

啊正常释放了?

为证明自己对是看起就老显的怀疑:重写addCell的setter方法,不开展其他保存:

@implementation BlockTable
-(void)setAddCell:(AddCellBlock)addCell
{

}

与此同时失去掉置为nil的代码:再运行看:

betway必威 10

计数器仍为2,而且为放了。

通过构思,出来了以下的下结论:

1:块的定义本身,就会造成1次引用,不过这次引用,在块离开所在的函数时,释放时,抵消掉引用数。

2:存档块的时候,会造成1次引用,而这个引用,是内存无法释放的原因。

4:根据上述解释,得到一个疯的定论:

只要block的代码只执行1次的,都可以任性的self或其它强引用。

事实上,我们写的代码,很多block的确只执行一次,不管是传的时候就执行,还是传完之后过段时间回调再执行。

认定只要执行1次的,就不需要WeakSelf,除非第三方框架的设计者造孽留坑,忘了在存档block执行后补上block=nil这一刀。

4:根据上述解释,得到一个癫狂的结论:

只要block的代码只执行1次的,都可以任性的self或其它强引用。

事实上,我们写的代码,很多block的确只执行一次,不管是传的时候就执行,还是传完之后过段时间回调再执行。

认定只要执行1次的,就不需要WeakSelf,除非第三方框架的设计者造孽留坑,忘了在存档block执行后补上block=nil这一刀。

5:消灭赋值的援计数:

此起彼伏表达想象力,既然存的早晚,会追加一次于引用,辣么,让她不搭引用不就哼了:

@implementation BlockTable
-(void)setAddCell:(AddCellBlock)addCell
{
    __weak AddCellBlock addCellWeak=addCell;
    _addCell=addCellWeak;
}

咱们先行让这block定义一个凋谢引用,然后还赋值给_addCell,运行看:

betway必威 11

哇草,成功了!计数器为2,正常释放了,看来好的想象力,还是得以的!!

连接下去,我们补充完善一下代码,增加一个reloadData方法,方法里调用事件。

完全的代码如下:

@interface BlockTable : NSObject

typedef void (^AddCellBlock)();
@property (nonatomic,copy)AddCellBlock addCell;

-(void)reloadData;
@end

@implementation BlockTable
-(void)setAddCell:(AddCellBlock)addCell
{
    __weak AddCellBlock addCellWeak=addCell;
    _addCell=addCellWeak;
}
-(void)reloadData
{
    if(self.addCell)
    {
        self.addCell();
     self.addCell();//没事来两次,模拟table多次循环清加cell
    }
}
-(void)dealloc
{
    NSLog(@"Table relase");
}
@end

修改一下多日志输出,现在重实施一下看望:

betway必威 12

一切看起来还相当周到,不需引入第三,需要频繁下的,只是在存的时段,存个弱引用,就做定了。

5:消灭赋值的援计数:

累表达想象力,既然存的当儿,会追加一不行引用,辣么,让它们不增加引用不就是吓了:

@implementation BlockTable
-(void)setAddCell:(AddCellBlock)addCell
{
    __weak AddCellBlock addCellWeak=addCell;
    _addCell=addCellWeak;
}

俺们事先为此block定义一个已故引用,然后再次赋值给_addCell,运行看:

betway必威 13

哇草,成功了!计数器为2,正常释放了,看来好的想象力,还是可以的!!

连通下去,我们加完善一下代码,增加一个reloadData方法,方法里调用事件。

整体的代码如下:

@interface BlockTable : NSObject

typedef void (^AddCellBlock)();
@property (nonatomic,copy)AddCellBlock addCell;

-(void)reloadData;
@end

@implementation BlockTable
-(void)setAddCell:(AddCellBlock)addCell
{
    __weak AddCellBlock addCellWeak=addCell;
    _addCell=addCellWeak;
}
-(void)reloadData
{
    if(self.addCell)
    {
        self.addCell();
     self.addCell();//没事来两次,模拟table多次循环清加cell
    }
}
-(void)dealloc
{
    NSLog(@"Table relase");
}
@end

改一下长日志输出,现在重实行一下看:

betway必威 14

一切看起来犹相当完美,不待引入第三,需要数动的,只是在存的上,存个弱引用,就将定了。

6:弱引用降低计数的短:

块的定义,和使用的场景,必须在同一个函数。

说白了就是块离开函数体就会消亡,所以要用要赶紧,且用且珍惜。

正常一个Table写了代码reloadData后,数据出来了。

6:弱引用降低计数的通病:

块的定义,和使用的场景,必须在同一个函数。

说白了就是块离开函数体就会消亡,所以要用要赶紧,且用且珍惜。

好端端一个Table写了代码reloadData后,数据出来了。

可若后面还和有一个刷新重新加载的成效?

倘若者更调用reloadData的地方,可能跟block不在和一个函数,比如代码像这么:

-(void)start
{
    BlockTable *table=[BlockTable new];
    self.table=table;//搞到全局变量中
    table.addCell = ^{
        __weak typeof(table) this=table;
        NSLog(@"addCell call");
    };
    [table reloadData];
    NSLog(@"table retain = %ld",CFGetRetainCount((__bridge CFTypeRef)(table)));
}
-(void)reflesh
{
    [self.table reloadData];
}

深受外界的类定义了一个table属性,然后调用完start后再调用reflesh,运行,会如何为?

betway必威 15

并发了IOS上极度可怕的EXC_BAD_ACCESS 野指针错误。

对于block离开函数后,消亡了好理解,只是这里:

及时什么是直丢弃大?哥不是作了判断了么?

为我们转移种代码写法:

betway必威 16

除此以外自高达图看:_addCell还是有值的。

为什么if(self.addCell)判断就直接死,if(_addCell)却没死呢?

正常self.addCell正常不是也return _addCell么?

这个问题,留给让你们思考了。

 

无限骇人听闻的,还是下面的即段话:

betway必威 17

但是如果后还和来一个刷新重新加载的功效?

假使者更调用reloadData的地方,可能跟block不在与一个函数,比如代码像这么:

-(void)start
{
    BlockTable *table=[BlockTable new];
    self.table=table;//搞到全局变量中
    table.addCell = ^{
        __weak typeof(table) this=table;
        NSLog(@"addCell call");
    };
    [table reloadData];
    NSLog(@"table retain = %ld",CFGetRetainCount((__bridge CFTypeRef)(table)));
}
-(void)reflesh
{
    [self.table reloadData];
}

为之外的类定义了一个table属性,然后调用完start后再次调用reflesh,运行,会怎样呢?

betway必威 18

起了IOS上极其骇人听闻的EXC_BAD_ACCESS 野指针错误。

对于block离开函数后,消亡了便于懂,只是这里:

当下什么是直丢弃大?哥不是犯了判断了么?

受咱换种代码写法:

betway必威 19

除此以外自高达图看:_addCell还是有值的。

为什么if(self.addCell)判断就直接死,if(_addCell)却没死呢?

正常self.addCell正常不是也return _addCell么?

这个问题,留给让你们思考了。

 

顶吓人的,还是下面的即时段话:

betway必威 20

7:避开野指针,仍是去世引用,功能未转移

OK,继续表达想象力,看看怎么避开野指针,同时还是促成上述的作用:

1:把block属性从copy改成weak

@property (nonatomic,weak)AddCellBlock addCell;

2:赋值代码手工copy:

-(void)setAddCell:(AddCellBlock)addCell
{
    addCell=[addCell copy];
    _addCell=addCell;
    //_addCell=[addCell copy];这样简写是不行的,不明白为虾米呢

    //    原来是这样写的:
    //   __weak AddCellBlock addCellWeak=addCell;
    //    _addCell=addCellWeak ;
}

双重运行,神奇的事体时有发生了:

betway必威 21

流程或大顺,不会见起野批针异常,Table也放了。

唯的不满,就是跳出函数后,block不克还复用了:

betway必威 22

7:避开野指针,仍是已故引用,功能未变换

OK,继续表达想象力,看看怎么避开野指针,同时还是促成上述的机能:

1:把block属性从copy改成weak

@property (nonatomic,weak)AddCellBlock addCell;

2:赋值代码手工copy:

-(void)setAddCell:(AddCellBlock)addCell
{
    addCell=[addCell copy];
    _addCell=addCell;
    //_addCell=[addCell copy];这样简写是不行的,不明白为虾米呢

    //    原来是这样写的:
    //   __weak AddCellBlock addCellWeak=addCell;
    //    _addCell=addCellWeak ;
}

再运行,神奇的事体闹了:

betway必威 23

流程或生顺,不会见出野批针异常,Table也释放了。

唯的缺憾,就是跳出函数后,block不能够还复用了:

betway必威 24

8:block的copy方法:

对于默认传进的block(有三种植形态:全局、栈、堆)

全局 copy 还是全局

堆 copy 还是堆

栈 copy 变成堆

说白了,copy只针对项目是仓库是才有效。

这是盖:栈的block,在尽完后出括号后,直接是绝迹对象。

设生死亡引用过去,会招野指针。

苟别少栽类型,销毁时,会用指针指向一个空指针。

addCell=[addCell copy] 和默认copy的属性 _addCell=addCell 也是执行了copy操作。

实践后,addCell的档次就改成堆形态,这样销毁的下,是空指针。

8:block的copy方法:

于默认传进的block(有三种植形态:全局、栈、堆)

全局 copy 还是全局

堆 copy 还是堆

栈 copy 变成堆

说白了,copy只对品种是仓库是才使得。

这是为:栈的block,在推行完后出括号晚,直接是绝迹对象。

要是起回老家引用过去,会导致野指针。

倘其余少种档次,销毁时,会拿指针指向一个空指针。

addCell=[addCell copy] 和默认copy的属性 _addCell=addCell 也是执行了copy操作。

施行后,addCell的品类就成为堆形态,这样销毁之时光,是空指针。

9:空指针和野指针的区别:

空指针:指向一个:人为创造的一个指针,它的名字叫空,有座空房子,里面什么也没有。

野指针:就是指向的都不知哪去了,连空房子都木有。

9:空指针和野指针的分别:

空指针:指向一个:人为创造的一个指针,它的名字叫空,有座空房子,里面什么也没有。

野指针:就是指向的都不知哪去了,连空房子都木有。

10:扩展想象力,如何消灭引用数,还能长期保留? 

死引用的弊端,就是block出了函数,就不再可用之block了。

那么还能怎么处置呢?没事,我还有想象力!!!!!

假若block可以重建为?

比如:

1:将block转成字符串存档,适当时机还原回来重新赋值

2:将block序列化保存,适当时机还原回来?

3:runtime读取block的__FuncPtr,存档再动态创建?

betway必威 25

伪代码大体如下:

-(void)setAddCell:(AddCellBlock)addCell
{
    addCell=[addCell copy];
    _addCell=addCell;

    //_addCell=[addCell copy];这样简写是不行的,不明白为虾米呢

    //    原来是这样写的:
    //   __weak AddCellBlock addCellWeak=addCell;
    //    _addCell=addCellWeak ;

    //存档block的字符串
}
-(void)reloadData
{
    if(!_addCell)
    {
        //从存档的block字符串还原block
        //_addCell=还原block
    }
    if(_addCell)
    {
        _addCell();
        _addCell();
    }
}

那就算剩下零星单问题?

1:怎么把block存档?

2:怎么将存档数据还原成block。

对搞C#的吧,这些还家常便饭,oc这块还未熟,有通的对象可顺路给支支招!!

10:扩展想象力,如何消灭引用数,还会长期保留? 

呜呼引用的弊病,就是block出了函数,就不再可用之block了。

那还能怎么收拾呢?没事,我还有想象力!!!!!

设block可以重建为?

比如:

1:将block转成字符串存档,适当时机还原回来重新赋值

2:将block序列化保存,适当时机还原回来?

3:runtime读取block的__FuncPtr,存档再动态创建?

betway必威 26

伪代码大体如下:

-(void)setAddCell:(AddCellBlock)addCell
{
    addCell=[addCell copy];
    _addCell=addCell;

    //_addCell=[addCell copy];这样简写是不行的,不明白为虾米呢

    //    原来是这样写的:
    //   __weak AddCellBlock addCellWeak=addCell;
    //    _addCell=addCellWeak ;

    //存档block的字符串
}
-(void)reloadData
{
    if(!_addCell)
    {
        //从存档的block字符串还原block
        //_addCell=还原block
    }
    if(_addCell)
    {
        _addCell();
        _addCell();
    }
}

这就是说就剩下零星单问题?

1:怎么把block存档?

2:怎么将存档数据还原成block。

对搞C#的吧,这些还家常便饭,oc这块还免熟,有由的情人可顺路给支支招!!

11:如果第10的艺术解决不了,就只能,只能,引入时机第三者了

唯独这个引入第三啊,只是一个机遇切入点,在此空子点的下,将其中的一样正在的援设置也nil。

譬如说Sagit框架的布局方面的时机,就摘在导航回退等事件被处理。

而这里需要一个稍微技巧:

于存档block时,不肯定要存即目标,也得为此一个合并的全局block管理起。

如此在工作处理时,根据作业情况,从大局block里来移除某些block即可。

具体在业务,所以这就是不进行了。

11:如果第10的章程解决不了,就只能,只能,引入时机第三者了

但是者引入第三啊,只是一个机遇切入点,在这空子点的时节,将其中的相同正在的援设置也nil。

比如说Sagit框架的布局方面的火候,就摘在导航回退等事件被处理。

但这里需要一个聊技巧:

在存档block时,不肯定要是有即目标,也得据此一个联合的全局block管理起来。

如此这般在工作处理时,根据工作情况,从大局block里来移除某些block即可。

现实在业务,所以这就是不进行了。

总结:

深信,一路拘留下,看懂了,后续的景况,基本上已为此不齐WeakSelf这东西了,因为像一个block,其生命周期必须和主人保持一致的,还是挺少的。

倘若这种少之情况,如果第10步解决了,基本就是都解决了,解决不了,还产生11。

深信读了此文,如果会一心知道,你就重为看不到block前WeakSelf这种,WeakSelf也没在必要了。

末段,欢迎大家关注IT连创业,虽然近年来自家都于折腾IOS,哈哈。

但IOS基础或要打劳,后续产品改良起来才发出质的飞跃。

总结:

信任,一路扣押下,看懂了,后续之情形,基本上就用非齐WeakSelf这东西了,因为像一个block,其生命周期必须同所有者保持一致的,还是挺少的。

设若这种少的状况,如果第10步解决了,基本就全解决了,解决不了,还来11。

信任读毕此文,如果能够完全了解,你就是又为看不到block前WeakSelf这种,WeakSelf也从来不在必要了。

末尾,欢迎大家关注IT连创业,虽然近年来自家还当折腾IOS,哈哈。

但是IOS基础还是如打劳,后续产品改良起来才发生质的快捷。

admin

网站地图xml地图