真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

一篇文章讓你看懂IOS中的block為何再也不需要WeakSelf弱引用

前言:

湘東網(wǎng)站制作公司哪家好,找成都創(chuàng)新互聯(lián)公司!從網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、響應(yīng)式網(wǎng)站建設(shè)等網(wǎng)站項(xiàng)目制作,到程序開發(fā),運(yùn)營(yíng)維護(hù)。成都創(chuàng)新互聯(lián)公司從2013年創(chuàng)立到現(xiàn)在10年的時(shí)間,我們擁有了豐富的建站經(jīng)驗(yàn)和運(yùn)維經(jīng)驗(yàn),來(lái)保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選成都創(chuàng)新互聯(lián)公司。

最近都在折騰Sagit架框的內(nèi)存釋放的問題,所以對(duì)這一塊有些心得。

對(duì)于新手,學(xué)到的文章都在教你用:typeof(self) __weak weakSelf = self

對(duì)于老手,可能早習(xí)慣了到處了WeakSelf了。

這次,就來(lái)學(xué)學(xué),如何不用WeakSelf。

1:從引用計(jì)數(shù)器開始:

這里先設(shè)計(jì)一個(gè)TableBlock類:

@interface BlockTable : NSObject

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

先這么簡(jiǎn)單,一個(gè)BlockTable只有一個(gè)block屬性,然后輸出一段釋放的日志。

@interface BlockTable : NSObject
typedef void (^AddCellBlock)();
@property (nonatomic,copy)AddCellBlock addCell;@end

接著,隨意找一個(gè)地方寫寫代碼:來(lái)new了一個(gè)BlockTable,并打印一下信息:

一篇文章讓你看懂IOS中的block為何再也不需要WeakSelf弱引用

這時(shí)候它的引用數(shù)是1,并且出了Table relase 。

接著給addCell屬性賦一個(gè)值,并運(yùn)行:

一篇文章讓你看懂IOS中的block為何再也不需要WeakSelf弱引用

一個(gè)空的事件,里面并沒有引用到table,所以引用數(shù)還是1。

2:開始循環(huán)引用

在block引用table,讓它產(chǎn)生循環(huán)引用,并運(yùn)行:

一篇文章讓你看懂IOS中的block為何再也不需要WeakSelf弱引用

我們看到:引用數(shù)變成了3,沒有輸出對(duì)象釋放信息了,為啥不是2呢?大大的問號(hào)??!

一個(gè)屬性賦值,為什么增強(qiáng)兩個(gè)引用計(jì)數(shù)?

3:猜解跳躍的計(jì)數(shù)器

接下來(lái),把屬性設(shè)置為nil,運(yùn)行看看:

一篇文章讓你看懂IOS中的block為何再也不需要WeakSelf弱引用

設(shè)置為nil,還有2?

也正常釋放了?

為了證實(shí)自己對(duì)這個(gè)看起來(lái)就很明顯的猜想:重寫addCell的setter方法,不進(jìn)行任何保存:

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

同時(shí)去掉置為nil的代碼:再運(yùn)行看看:

一篇文章讓你看懂IOS中的block為何再也不需要WeakSelf弱引用

計(jì)數(shù)器仍為2,而且也釋放了。

經(jīng)過思考,出來(lái)了以下的結(jié)論:

     1:塊的定義本身,就會(huì)造成1次引用,不過這次引用,在塊離開所在的函數(shù)時(shí),釋放時(shí),抵消掉引用數(shù)。

     2:存檔塊的時(shí)候,會(huì)造成1次引用,而這個(gè)引用,是內(nèi)存無(wú)法釋放的原因。

4:根據(jù)上述解釋,得到一個(gè)瘋狂的結(jié)論:

只要block的代碼只執(zhí)行1次的,都可以任性的self或其它強(qiáng)引用。

事實(shí)上,我們寫的代碼,很多block的確只執(zhí)行一次,不管是傳的時(shí)候就執(zhí)行,還是傳完之后過段時(shí)間回調(diào)再執(zhí)行。

認(rèn)定只要執(zhí)行1次的,就不需要WeakSelf,除非第三方框架的設(shè)計(jì)者造孽留坑,忘了在存檔block執(zhí)行后補(bǔ)上block=nil這一刀。

5:消滅賦值的引用計(jì)數(shù):

繼續(xù)發(fā)揮想象力,既然存的時(shí)候,會(huì)增加一次引用,辣么,讓它不增加引用不就好了:

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

我們先給這個(gè)block定義一個(gè)弱引用,然后再賦值給_addCell,運(yùn)行看看:

一篇文章讓你看懂IOS中的block為何再也不需要WeakSelf弱引用

哇草,成功了!計(jì)數(shù)器為2,正常釋放了,看來(lái)自己的想象力,還是可以的?。?/p>

接下來(lái),我們補(bǔ)充完善一下代碼,增加一個(gè)reloadData方法,方法里調(diào)用事件。

完整的代碼如下:

@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();//沒事來(lái)兩次,模擬table多次循環(huán)清加cell
 }
}
-(void)dealloc
{
 NSLog(@"Table relase");
}
@end

修改一下增加日志輸出,現(xiàn)在再執(zhí)行一下看看:

一篇文章讓你看懂IOS中的block為何再也不需要WeakSelf弱引用

一切看起來(lái)都相當(dāng)完美,不需要引入第三,需要多次使用的,只是在存的時(shí)候,存?zhèn)€弱引用,就搞定了。

6:弱引用降低計(jì)數(shù)的缺陷:

塊的定義,和使用的場(chǎng)景,必須在同一個(gè)函數(shù)。

說(shuō)白了就是塊離開函數(shù)體就會(huì)消亡,所以要用要趕緊,且用且珍惜。

正常一個(gè)Table寫完代碼reloadData后,數(shù)據(jù)出來(lái)了。

但如果后面還跟有一個(gè)刷新重新加載的功能?

而這個(gè)重新調(diào)用reloadData的地方,可能跟block不在同一個(gè)函數(shù),比如代碼像這樣:

-(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];
}

給外面的類定義了一個(gè)table屬性,然后調(diào)用完start后再調(diào)用reflesh,運(yùn)行,會(huì)怎樣呢?

一篇文章讓你看懂IOS中的block為何再也不需要WeakSelf弱引用

出現(xiàn)了IOS上最可怕的EXC_BAD_ACCESS 野指針錯(cuò)誤。

對(duì)于block離開函數(shù)后,消亡了容易理解,只是這里:

這什么是直接拋異常?哥不是作了判斷了么?

讓我們換種代碼寫法:

一篇文章讓你看懂IOS中的block為何再也不需要WeakSelf弱引用

另外從上圖看:_addCell還是有值的。

為什么if(self.addCell)判斷就直接死,if(_addCell)卻沒死呢?

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

這個(gè)問題,留給讓你們思考了。

最可怕的,還是下面的這段話:

一篇文章讓你看懂IOS中的block為何再也不需要WeakSelf弱引用

7:避開野指針,仍是弱引用,功能不變

OK,繼續(xù)發(fā)揮想象力,看看怎么避開野指針,同時(shí)還是實(shí)現(xiàn)上述的效果:

1:把block屬性從copy改成weak

@property (nonatomic,weak)AddCellBlock addCell;

2:賦值代碼手工copy:

-(void)setAddCell:(AddCellBlock)addCell
{
 addCell=[addCell copy];
 _addCell=addCell;
 //_addCell=[addCell copy];這樣簡(jiǎn)寫是不行的,不明白為蝦米呢
 
 // 原來(lái)是這樣寫的:
 // __weak AddCellBlock addCellWeak=addCell;
 // _addCell=addCellWeak ;
}

再次運(yùn)行,神奇的事情發(fā)生了:

一篇文章讓你看懂IOS中的block為何再也不需要WeakSelf弱引用

流程還是很順,不會(huì)有野批針異常,Table也釋放了。

唯一的遺憾,就是跳出函數(shù)后,block不能再?gòu)?fù)用了:

一篇文章讓你看懂IOS中的block為何再也不需要WeakSelf弱引用

8:block的copy方法:

對(duì)于默認(rèn)傳進(jìn)來(lái)的block(有三種形態(tài):全局、棧、堆)

全局 copy 還是全局

堆 copy 還是堆

棧 copy 變成堆

說(shuō)白了,copy只對(duì)類型是棧是才有效。

這是因?yàn)椋簵5腷lock,在執(zhí)行完后出括號(hào)后,直接是銷毀對(duì)象。

如果有弱引用過去,會(huì)造成野指針。

而其它兩種類型,銷毀時(shí),會(huì)將指針指向一個(gè)空指針。

addCell=[addCell copy] 和默認(rèn)copy的屬性 _addCell=addCell 也是執(zhí)行了copy操作。

執(zhí)行后,addCell的類型就變成堆形態(tài),這樣銷毀的時(shí)候,是空指針。

9:空指針和野指針的區(qū)別:

空指針:指向一個(gè):人為創(chuàng)造的一個(gè)指針,它的名字叫空,有座空房子,里面什么也沒有。

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

10:擴(kuò)展想象力,如何消滅引用數(shù),還能長(zhǎng)久保留?

弱引用的壞處,就是block出了函數(shù),就不再可用這個(gè)block了。

那還能怎么辦呢?沒事,我還有想象力?。。。?!

如果block可以重建呢?

比如:

1:將block轉(zhuǎn)成字符串存檔,適當(dāng)時(shí)機(jī)還原回來(lái)重新賦值

2:將block序列化保存,適當(dāng)時(shí)機(jī)還原回來(lái)?

3:runtime讀取block的__FuncPtr,存檔再動(dòng)態(tài)創(chuàng)建?

一篇文章讓你看懂IOS中的block為何再也不需要WeakSelf弱引用

偽代碼大體如下:

-(void)setAddCell:(AddCellBlock)addCell
{
 addCell=[addCell copy];
 _addCell=addCell;
 
 //_addCell=[addCell copy];這樣簡(jiǎn)寫是不行的,不明白為蝦米呢
 // 原來(lái)是這樣寫的:
 // __weak AddCellBlock addCellWeak=addCell;
 // _addCell=addCellWeak ;
 
 //存檔block的字符串
}
-(void)reloadData
{
 if(!_addCell)
 {
 //從存檔的block字符串還原block
 //_addCell=還原block
 }
 if(_addCell)
 {
 _addCell();
 _addCell();
 }
}

那么就剩下兩個(gè)問題?

1:怎么把block存檔?

2:怎么將存檔數(shù)據(jù)還原成block。

對(duì)搞C#的來(lái)說(shuō),這些都家常便飯,oc這塊還不熟,有路過的朋友可順路給支支招!!

11:如果第10的方式解決不了,就只能,只能,引入時(shí)機(jī)第三者了

不過這個(gè)引入第三者,只是一個(gè)時(shí)機(jī)切入點(diǎn),在這個(gè)時(shí)機(jī)觸發(fā)的時(shí)候,將其中的一方的引用設(shè)置為nil。

像Sagit框架的布局方面的時(shí)機(jī),就選在導(dǎo)航回退等事件中處理。

不過這里需要一個(gè)小技巧:

在存檔block時(shí),不一定要存在當(dāng)前對(duì)象,也可以用一個(gè)統(tǒng)一的全局block管理起來(lái)。

這樣在業(yè)務(wù)處理時(shí),根據(jù)業(yè)務(wù)情況,從全局block里來(lái)移除某些block即可。

具體取決于業(yè)務(wù),所以這個(gè)就不展開了。

總結(jié):

相信,一路看下,看懂了,后續(xù)的情況,基本上已經(jīng)用不上WeakSelf這東西了,因?yàn)橄褚粋€(gè)block,其生命周期必須和持有者保持一致的,還是挺少的。

而這種少的情況,如果第10步解決了,基本就全都解決了,解決不了,還有11。

相信讀完此文,如果能完全理解,你就再也看不到block前WeakSelf這種,WeakSelf也沒有存在必要了。

最后,歡迎大伙關(guān)注IT連創(chuàng)業(yè),雖然最近我都在折騰IOS,哈哈。

不過IOS基礎(chǔ)還是要打勞,后續(xù)產(chǎn)品改進(jìn)起來(lái)才有質(zhì)的飛躍。

好了,以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)創(chuàng)新互聯(lián)的支持。


文章標(biāo)題:一篇文章讓你看懂IOS中的block為何再也不需要WeakSelf弱引用
文章轉(zhuǎn)載:http://weahome.cn/article/gphoed.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部