棧塊、堆塊潘靖、全局塊

編譯器版本為Clang5穿剖,主要技術(shù)是ARC,參考來自Objective-C Automatic Reference Counting (ARC)

block根據(jù)分配的內(nèi)存位置分為棧塊卦溢,堆塊糊余,全局塊。

一個(gè)block在創(chuàng)建的時(shí)候既绕,就可以確定其類型啄刹,判斷一個(gè)block是那種類型其實(shí)很簡(jiǎn)單,規(guī)則如下(MRC和ARC都適用):

1.如果一個(gè)block中引用了全局變量凄贩,或者沒有引用任何外部變量(屬性誓军、實(shí)例變量、局部變量)疲扎,那么該block為全局塊昵时。
2.其它引用情況(局部變量,實(shí)例變量椒丧,屬性)為棧塊壹甥。

上面的規(guī)則中并不存在堆塊的判斷,因?yàn)橐陨弦?guī)則的前提條件是:block在創(chuàng)建的時(shí)候壶熏,不是創(chuàng)建完之后賦值給變量句柠,代碼如下:

@interface MGBlockExample()
//屬性
@property(nonatomic,assign)int a;

@end
@implementation MGBlockExample{
    int _b; //實(shí)例變量
}
//全局變量
int c = 3;

- (void)test{
    
    /*****      全局塊        *****/
    
    //引用全局變量
    NSLog(@"aBlock:%@", ^{ NSLog(@"c:%d",c); }); //aBlock:__NSGlobalBlock__
    
    //沒有引用變量
    NSLog(@"bBlock:%@", ^{ NSLog(@""); }); //bBlock:__NSGlobalBlock__
    
    
    /*****       棧塊        *****/
    
    int d = 4;
    //不給賦值,但引用了局部變量
    NSLog(@"cBlock:%@",^void{ NSLog(@"d:%d",d); }); //cBlock:__NSStackBlock__
    //不給賦值棒假,但引用了實(shí)例變量
    NSLog(@"dBlock:%@",^void{ NSLog(@"_b:%d",_b); }); //dBlock:__NSStackBlock__
    //不給賦值溯职,但引用了屬性
    NSLog(@"eBlock:%@",^void{ NSLog(@"self.a:%d",self.a); }); //eBlock:__NSStackBlock__
}
@end

全局塊和棧塊已經(jīng)有規(guī)則可以判斷,并且適用于MRC和ARC帽哑,規(guī)則的前提條件是block創(chuàng)建的時(shí)候谜酒。那么在將創(chuàng)建完的塊之后賦值給變量會(huì)出現(xiàn)什么情況呢?看下面代碼:

- (void)test1{
    //局部變量
    void (^fBlock)() = ^(){
        NSLog(@"d:%d",d);
    };
    
    //實(shí)例變量
    void (^gBlock)() = ^(){
        NSLog(@"_b:%d",_b);
    };
    
    //屬性
    void (^hBlock)() = ^(){
        NSLog(@"self.a:%d",self.a);
    };
    NSLog(@"fBlock:%@", fBlock); 
    NSLog(@"gBlock:%@", gBlock); 
    NSLog(@"hBlock:%@", hBlock); 
    //MRC:上面操作輸出//XBlock:__NSStackBlock__
    //ARC:上面操作輸出//XBlock: __NSMallocBlock__
}

從上面代碼可以看到在MRC環(huán)境中妻枕,block引用局部變量僻族、實(shí)例變量、屬性的的結(jié)果依然是生成棧塊屡谐。而在ARC環(huán)境中述么,生成的是堆塊。原因如下:

block是retainable object pointer類型愕掏。

在ARC環(huán)境中度秘,ARC會(huì)對(duì)retainable type進(jìn)行內(nèi)存管理:

If an object is declared with retainable object owner type, but without an explicit ownership qualifier, its type is implicitly adjusted to have __strong qualification.
如果一個(gè)被定義對(duì)象是retainable object owner類型,并且沒有明確指定內(nèi)存管理策略亭珍,那么編譯器會(huì)默認(rèn)為其添加__strong修飾詞敷钾。

所以上面的fBlock在ARC環(huán)境中是這樣的:

__strong void (^fBlock)() = ^(){
        NSLog(@"d:%d",d);
    };

然后document又說:

With the exception of retains done as part of initializing a __strong parameter variable or reading a __weak variable, whenever these semantics call for retaining a value of block-pointer type, it has the effect of a Block_copy. The optimizer may remove such copies when it sees that the result is used only as an argument to a call.
對(duì)于block來說,不管是在創(chuàng)建對(duì)象的時(shí)候strong修飾還是在讀取weak修飾的變量肄梨,其效果和用Block_copy修飾是一樣的阻荒。當(dāng)編譯器覺得可以優(yōu)化的時(shí)候就不會(huì)執(zhí)行Block_copy函數(shù),例如一個(gè)block初始化完之后就被當(dāng)做一個(gè)參數(shù)使用了(例如cBlock众羡、dBlock侨赡、eBlock)

所以上面fBlock的代碼轉(zhuǎn)成MRC是類似這樣的:

void (^fBlock)() = [^(){
        NSLog(@"d:%d",d);
    } copy];

給block對(duì)象的-copy方法發(fā)送消息,會(huì)將該對(duì)象拷貝一份放入堆中粱侣,所以這個(gè)時(shí)候塊從棧塊變成堆塊羊壹。


補(bǔ)充一下block的內(nèi)存管理

不管是對(duì)block進(jìn)行retiancopy齐婴、release,block的引用計(jì)數(shù)都不會(huì)增加油猫,始終為1。

NSGlobalBlock:使用retain柠偶、copy情妖、release都無效,block依舊存在全局區(qū)诱担,且沒有釋放, 使用copyretian只是返回block的指針毡证。

NSStackBlock:使用retainrelease操作無效蔫仙;棧區(qū)block會(huì)在方法返回后將block空間回收料睛; 使用copy將棧區(qū)block復(fù)制到堆區(qū),可以長(zhǎng)久保留block的空間摇邦,以供后面的程序使用恤煞。

NSMallocBlock:支持retianrelease涎嚼,雖然block的引用計(jì)數(shù)始終為1阱州,但內(nèi)存中還是會(huì)對(duì)引用進(jìn)行管理,使用retain引用+1法梯, release引用-1苔货; 對(duì)于NSMallocBlock使用copy之后不會(huì)產(chǎn)生新的block,只是增加了一次引用立哑,類似于使用retian夜惭。

總結(jié)起來是這樣的:

1.在創(chuàng)建block的時(shí)候(MRC和ARC通用):

1.1. 如果一個(gè)block中引用了全局變量,或者沒有引用任何外部變量(屬性铛绰、實(shí)例變量诈茧、局部變量),那么該block為全局塊捂掰。
1.2. 其它引用情況(局部變量敢会,實(shí)例變量曾沈,屬性)為棧塊。

2.在將block對(duì)象賦值給其它對(duì)象^(oBlock)()的時(shí)候(ARC):

2.1. 如果block是棧塊鸥昏,那么oBlock變成堆塊(因?yàn)镃lang編譯器幫我們往block發(fā)送了copy消息)塞俱。
2.2. 如果block是全局塊,那么oBlock也是全局塊吏垮,如果block是堆塊障涯,那么oBlock也是堆塊。
2.3. 如果僅把創(chuàng)建完的 block 當(dāng)做方法參數(shù)使用(不進(jìn)行其它賦值引用)膳汪,那么 block 的類型不變(參照1.1和1.2的情況)唯蝶。

3.在將block對(duì)象賦值給其它對(duì)象^(oBlock)()的時(shí)候(MRC):

3.1. block是什么,oBlock便是什么遗嗽。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末粘我,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子痹换,更是在濱河造成了極大的恐慌涂滴,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件晴音,死亡現(xiàn)場(chǎng)離奇詭異柔纵,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)锤躁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門搁料,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人系羞,你說我怎么就攤上這事郭计。” “怎么了椒振?”我有些...
    開封第一講書人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵昭伸,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我澎迎,道長(zhǎng)庐杨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任夹供,我火速辦了婚禮灵份,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘哮洽。我一直安慰自己填渠,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著氛什,像睡著了一般莺葫。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上枪眉,一...
    開封第一講書人閱讀 49,730評(píng)論 1 289
  • 那天徙融,我揣著相機(jī)與錄音,去河邊找鬼瑰谜。 笑死,一個(gè)胖子當(dāng)著我的面吹牛树绩,可吹牛的內(nèi)容都是我干的萨脑。 我是一名探鬼主播,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼饺饭,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼渤早!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起瘫俊,我...
    開封第一講書人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤鹊杖,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后扛芽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體骂蓖,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年川尖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了登下。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡叮喳,死狀恐怖被芳,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情馍悟,我是刑警寧澤畔濒,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站锣咒,受9級(jí)特大地震影響侵状,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜毅整,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一壹将、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧毛嫉,春花似錦诽俯、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽闯团。三九已至,卻和暖如春仙粱,著一層夾襖步出監(jiān)牢的瞬間房交,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工伐割, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留候味,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓隔心,卻偏偏與公主長(zhǎng)得像白群,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子硬霍,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

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

  • 內(nèi)存管理 簡(jiǎn)述OC中內(nèi)存管理機(jī)制帜慢。與retain配對(duì)使用的方法是dealloc還是release,為什么唯卖?需要與a...
    丶逐漸閱讀 1,950評(píng)論 1 16
  • 《Objective-C高級(jí)編程》這本書就講了三個(gè)東西:自動(dòng)引用計(jì)數(shù)粱玲、block、GCD拜轨,偏向于從原理上對(duì)這些內(nèi)容...
    WeiHing閱讀 9,804評(píng)論 10 69
  • iOS代碼塊Block 概述 代碼塊Block是蘋果在iOS4開始引入的對(duì)C語言的擴(kuò)展,用來實(shí)現(xiàn)匿名函數(shù)的特性,B...
    smile刺客閱讀 2,333評(píng)論 2 26
  • *面試心聲:其實(shí)這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個(gè)offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,128評(píng)論 29 470
  • 為什么進(jìn)行內(nèi)存管理抽减? 由于移動(dòng)設(shè)備的內(nèi)存極其有限,所以每個(gè)APP所占的內(nèi)存也是有限制的橄碾,當(dāng)app所占用的內(nèi)存較多時(shí)...
    天天想念閱讀 889評(píng)論 1 7