深入Block內(nèi)存管理

Block類型

根據(jù)Block在內(nèi)存中的位置吼肥,系統(tǒng)把Block分為3類:NSGlobalBlock眼俊,NSStackBlock,NSMallocBlock;

NSGlobalBlock:位于內(nèi)存全局區(qū)

NSStackBlock:位于內(nèi)存棧區(qū)

NSMallocBlock:位于內(nèi)存堆區(qū)

我們通過block引用不同的變量來

全局區(qū)block(NSGlobalBlock)

沒有引用局部變量的block叫做NSGlobalBlock拷橘,如下實例:

//類型1:沒有使用任何外部變量-(void)test{void(^gBlock1)(int,int) =^(inta,intb){NSLog(@"a + b = %d", a+b);? ? };NSLog(@"%@", gBlock1);//打印結(jié)果為://<__NSGlobalBlock__: 0x1025e8110>}//類型2:使用全局變量//全局變量inta =10;-(void)test{void(^gBlock)() = ^(){NSLog(@"%d", a);? ? };NSLog(@"%@", gBlock);//輸出結(jié)果為://<__NSGlobalBlock__: 0x103676110>}

棧區(qū)block(NSStackBlock)

引用了局部變量的block叫做NSStackBlock途戒, 實例如下:

-(void)test{//局部變量NSArray*arr = @[@"zhangsan",@"lisi"];void(^sBlock)() = ^(){NSLog(@"arr = %@", arr);? ? };NSLog(@"%@", sBlock);//輸出結(jié)果為://<__NSStackBlock__: 0x7fff5bbf1a58>}

PS:棧區(qū)block在方法返回后就會被釋放愈魏,所以只能在方法內(nèi)部使用搭综,如果將他賦值給其他對象或者存儲起來筹淫,后面使用時將會出現(xiàn)錯誤.

堆區(qū)Block(NSMallocBlock)

在非ARC下站辉,我們一般不手動創(chuàng)建NSMallocBlock,我們把從棧區(qū)復制(copy)過來的block稱為堆區(qū)block损姜。實例如下:

-(void)test{NSArray*arr = @[@"zhangsan",@"lisi"];//棧區(qū)blockvoid(^sBlock)() = ^(){NSLog(@"arr = %@", arr);? ? };NSLog(@"%@", sBlock);//堆區(qū)blockvoid(^mBlock)() = [sBlockcopy];NSLog(@"%@", mBlock);//輸出結(jié)果為://<__NSStackBlock__: 0x7fff59bf9a38>//<__NSMallocBlock__: 0x7fc173f0dd80>}

Block內(nèi)存管理

對block自身內(nèi)存的管理

對于block饰剥,有兩個內(nèi)存管理方法:Block_copy,Block_release;Block_copy與copy等效,Block_release與release等效摧阅;

不管是對block進行retian,copy,release,block的引用計數(shù)都不會增加汰蓉,始終為1;

NSGlobalBlock:使用retain,copy,release都無效棒卷,block依舊存在全局區(qū)古沥,且沒有釋放, 使用copy和retian只是返回block的指針瘸右;

NSStackBlock:使用retain,release操作無效;棧區(qū)block會在方法返回后將block空間回收岩齿; 使用copy將棧區(qū)block復制到堆區(qū)太颤,可以長久保留block的空間,以供后面的程序使用盹沈;

NSMallocBlock:支持retian,release龄章,雖然block的引用計數(shù)始終為1,但內(nèi)存中還是會對引用進行管理乞封,使用retain引用+1做裙,release引用-1; 對于NSMallocBlock使用copy之后不會產(chǎn)生新的block肃晚,只是增加了一次引用锚贱,類似于使用retian;

對引用變量的內(nèi)存管理

在block中經(jīng)常會用到外部變量/對象,如果這個block是存儲在堆區(qū)关串,或者被復制到堆區(qū)拧廊,則對象對應的實例引用+1,當block釋放后block的引用-1晋修;

-(void)test{NSArray*arr = @[@"zhangsan",@"lisi"];NSLog(@"arr.retianCount = %ld", arr.retainCount);//棧區(qū)blockvoid(^sBlock)() = ^(){NSLog(@"arr = %@", arr);? ? };//棧區(qū)block不會對引用的變量引用計數(shù)+1NSLog(@"arr.retianCount = %ld", arr.retainCount);//堆區(qū)blockvoid(^mBlock)() = [sBlockcopy];//復制到堆區(qū)后吧碾,引用計數(shù)+1NSLog(@"arr.retianCount = %ld", arr.retainCount);}

循環(huán)引用

因為block中會對引用的對象進行持有(引用計數(shù)+1),從而導致相互持有引起循環(huán)引用;解決這種問題的方式是對引用變量使用修飾詞__block或者__weak;

__block:在非ARC中使用墓卦,NSMallocBlock類型的block不會對__block修飾的的變量引用計數(shù)+1倦春,從而消除循環(huán)引用;在ARC中使用__block無效

__weak:在ARC中使用落剪,作用和__block一樣睁本,從而消除循環(huán)引用;在非ARC中不可以使用__weak;

防止循環(huán)引用案例:

//TestClass.h

@interfacetestClass: NSObject@property(nonatomic, copy)void (^myBlock)(void);@end

//TestClass.m

#define TestClassExample3 1@implementationTestClass-(void)dealloc{NSLog(@"測試對象 被釋放了忠怖。添履。。");? ? [superdealloc];}-(instancetype)init{self= [superinit];if(self) {#if TestClassExample1//會引起循環(huán)應用脑又,當前對象無法被釋放self.myBlock = ^(){//增加自己本身的引用計數(shù)[selfdoSomething];? ? ? ? };#elif TestClassExample2//在非ARC下有效暮胧,防止循環(huán)引用//在ARC下無效,會產(chǎn)生循環(huán)引用__block TestClass *weakSelf =self;self.myBlock = ^(){//在非ARC下不會增加self的引用計數(shù)[weakSelf doSomething];? ? ? ? };#elif TestClassExample3//在非ARC下無效问麸,會產(chǎn)生循環(huán)引用//在ARC下有效往衷,防止循環(huán)應用__weakTestClass *weakSelf =self;self.myBlock = ^(){//在非ARC下不會增加self的引用計數(shù)[weakSelf doSomething];? ? ? ? };#endif}returnself;}-(void)doSomething{NSLog(@"測試程序");}@end

//main.h

intmain(intargc,char* argv[]){@autoreleasepool{? ? ? ? TestClass *tc = [[TestClass alloc] init];? ? ? ? [tc release];? ? ? ? tc = nil;? ? }}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市严卖,隨后出現(xiàn)的幾起案子席舍,更是在濱河造成了極大的恐慌,老刑警劉巖哮笆,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件来颤,死亡現(xiàn)場離奇詭異汰扭,居然都是意外死亡,警方通過查閱死者的電腦和手機福铅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門萝毛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人滑黔,你說我怎么就攤上這事笆包。” “怎么了略荡?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵庵佣,是天一觀的道長。 經(jīng)常有香客問我汛兜,道長巴粪,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任粥谬,我火速辦了婚禮肛根,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘帝嗡。我一直安慰自己,他們只是感情好璃氢,可當我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布哟玷。 她就那樣靜靜地躺著,像睡著了一般一也。 火紅的嫁衣襯著肌膚如雪巢寡。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天椰苟,我揣著相機與錄音抑月,去河邊找鬼。 笑死舆蝴,一個胖子當著我的面吹牛谦絮,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播洁仗,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼层皱,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了赠潦?” 一聲冷哼從身側(cè)響起叫胖,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎她奥,沒想到半個月后瓮增,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體怎棱,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年绷跑,在試婚紗的時候發(fā)現(xiàn)自己被綠了拳恋。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡你踩,死狀恐怖诅岩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情带膜,我是刑警寧澤吩谦,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站膝藕,受9級特大地震影響式廷,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜芭挽,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一滑废、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧袜爪,春花似錦蠕趁、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至昙篙,卻和暖如春腊状,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背苔可。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工缴挖, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人焚辅。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓映屋,卻偏偏與公主長得像,于是被迫代替她去往敵國和親同蜻。 傳聞我的和親對象是個殘疾皇子秧荆,可洞房花燭夜當晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 前言 Blocks是C語言的擴充功能,而Apple 在OS X Snow Leopard 和 iOS 4中引入了這...
    小人不才閱讀 3,768評論 0 23
  • Block簡介(copy一段) Block作為C語言的擴展埃仪,并不是高新技術(shù)乙濒,和其他語言的閉包或lambda表達式是...
    qui丶MyLove閱讀 422評論 0 0
  • Block 梳理與疑問 時隔一年,再次讀 《Objective-C 高級編程》,看到 block 一章颁股,這一次從頭...
    DeerRun閱讀 632評論 0 2
  • iOS代碼塊Block 概述 代碼塊Block是蘋果在iOS4開始引入的對C語言的擴展,用來實現(xiàn)匿名函數(shù)的特性,B...
    smile刺客閱讀 2,347評論 2 26
  • 昨天你丟了甘有,估計就在我出門的一瞬間诉儒,我只聽見嗖的一下,轉(zhuǎn)頭卻什么也沒看見亏掀,你應該就是那時偷偷往樓上跑了忱反。 晚上回來...
    韓小喵閱讀 279評論 0 0