[iOS]Block系列探究四 - __block變量存儲域

上一篇文章研究了一下Block的存儲域幔烛,這一篇文章我們來研究下__block變量的存儲域。

一稽莉、__block變量不能聲明為全局變量

當我們將__block聲明為全局變量的時候,代碼如下:

// 聲明為全局變量
__block int global_val = 10;

int main(int argc, const char * argv[]) {
    ...
    return 0;
}

會報錯,報錯信息為__block attribute not allowed, only allowed on local variables敬特。
為什么會報錯呢?其實也比較容易理解牺陶,__block這個屬性的出現(xiàn)就是為了解決Block內(nèi)部不能修改局部變量的問題伟阔。可是全局變量沒有這個問題掰伸,就不要多此一舉了皱炉。

二、__block變量的存儲域

從第一節(jié)的報錯信息__block attribute not allowed, only allowed on local variables可以看出狮鸭,__block屬性只能用來修飾局部變量合搅,那么下面就引出了__block變量的存儲域以及Block從棧復制到堆時對__block變量產(chǎn)生的影響。

2.1 __block存儲在棧上

我們首先來想象一種場景歧蕉,__block屬性修飾的局部變量(非對象)灾部,從創(chuàng)建到到被棧BLock使用時,__block變量時存儲在哪個區(qū)域呢惯退?
先說答案赌髓,以下兩種情況,__block存儲在棧上:

  • (非對象)剛初始化時;
  • 被棧BLock使用時锁蠕。

2.1.1 (非對象)剛初始化時

__block變量剛初始化時的代碼如下:

int main(int argc, const char * argv[]) {
    
    // 聲明為局部變量
    __block int val = 10;
    // 這個局部變量作為地址對比
    int num = 10;
    
    NSLog(@"__block變量的地址:%p -- 局部變量的地址:%p", &val, &num);
    
    return 0;
}

控制臺打印語句如下:

__block變量的地址:0x7ffeefbff578 -- 局部變量的地址:0x7ffeefbff55c

我們可以看到夷野,__block變量的地址和普通局部變量的地址是挨著的,所以剛初始化時的__block變量存儲在棧上荣倾。

2.1.2 被棧Block使用

__block變量被棧BLock使用的代碼如下:

int main(int argc, const char * argv[]) {
    
    // 聲明為局部變量
    __block int val = 10;
    // 這個局部變量作為地址對比
    int num = 10;
    
    void (^__weak block)(void) = ^{
        val = 11;
    };
    
    block();
    
    NSLog(@"__block變量的地址:%p -- 局部變量的地址:%p", &val, &num);
    
    return 0;
}

控制臺打印語句如下:

__block變量的地址:0x7ffeefbff588 -- 局部變量的地址:0x7ffeefbff56c

我們可以看到扫责,__block變量的地址和普通局部變量的地址是挨著的,所以被棧Block使用的__block變量存儲在棧上(__block變量沒有被強引用)逃呼。

2.2 __block存儲在堆上

我們知道了存儲在棧上的__block變量被棧BLock使用時鳖孤,__block變量并沒有拷貝到堆上,那么__block變量被堆BLock使用時抡笼,會發(fā)生什么呢苏揣?我們來探究一下。
上代碼:

int main(int argc, const char * argv[]) {
    
    // 聲明為局部變量
    __block int val = 10;
    // 這個對象作為地址對比
    People *people = [[People alloc] init];
    
    void (^block)(void) = ^{
        val = 11;
    };
    
    block();
    
    NSLog(@"__block變量的地址:%p -- 對象的地址:%@", &val, people);
    
    return 0;
}

控制臺打印如下:

__block變量的地址:0x100704828 -- 對象的地址:<People: 0x100706b90>

我們可以看到推姻,當存儲在棧上的__block變量被棧BLock使用時平匈,__block變量被拷貝到了堆上(被堆BLock強引用)。
我們把NSLog(@"__block變量的地址:%p -- 對象的地址:%@", &val, people);這句代碼clang一下藏古,看看到底發(fā)生了什么:

NSLog((NSString *)&__NSConstantStringImpl__var_folders_0r_hkkmpct143n4wd3xxk0l1j8c0000gn_T_main_c842f2_mi_0, &(val.__forwarding->val), people);

重溫一下__block變量的結構體:

struct __Block_byref_val_0 {
  void *__isa;
__Block_byref_val_0 *__forwarding;
 int __flags;
 int __size;
 int val;
};

我們可以看到增炭,使用val這個__block變量時,其實是使用了val.__forwarding->val這個值拧晕。

所以我們可以猜測,當__block變量初始化在棧上時隙姿,__forwarding這個成員變量一開始指向的是棧上的__block變量,但是在__block變量拷貝了一份在堆上時厂捞,__forwarding成員變量指向了堆上的__block變量输玷。所以不管是在Block內(nèi)還是BLock外我們訪問的都是同一個__block變量。

2.2 __block被多個堆BLock使用

其實我們已經(jīng)探討好了__block變量的存儲域靡馁,就是棧和堆欲鹏。那么一個__block變量被多個堆Block使用時會發(fā)生什么呢?
其實__block變量本質上是一個對象臭墨,所以每被一個堆BLock使用時赔嚎,就代表被強引用一次,__block變量的引用計數(shù)+1胧弛,這個和OC的引用計數(shù)式內(nèi)存管理是完全一樣的尤误。



最后我們用一個表格來結束今天的文章。
BLock從棧賦值到堆時對__block變量產(chǎn)生額影響:

__block變量的配置存儲域 BLock從棧賦值到堆時的影響
從椧镀裕拷貝到堆上并被Block持有袄膏,__forwarding指向堆上的__block對象
被Block持有,引用計數(shù)+1
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末掺冠,一起剝皮案震驚了整個濱河市沉馆,隨后出現(xiàn)的幾起案子码党,更是在濱河造成了極大的恐慌,老刑警劉巖斥黑,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件揖盘,死亡現(xiàn)場離奇詭異,居然都是意外死亡锌奴,警方通過查閱死者的電腦和手機兽狭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鹿蜀,“玉大人箕慧,你說我怎么就攤上這事≤钋。” “怎么了颠焦?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長往枣。 經(jīng)常有香客問我伐庭,道長,這世上最難降的妖魔是什么分冈? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任圾另,我火速辦了婚禮,結果婚禮上雕沉,老公的妹妹穿的比我還像新娘集乔。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布序调。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪寨蹋。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天谦絮,我揣著相機與錄音羞延,去河邊找鬼。 笑死梢睛,一個胖子當著我的面吹牛肥印,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播绝葡,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼深碱,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了藏畅?” 一聲冷哼從身側響起敷硅,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后绞蹦,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體力奋,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年幽七,在試婚紗的時候發(fā)現(xiàn)自己被綠了景殷。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡澡屡,死狀恐怖猿挚,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情驶鹉,我是刑警寧澤亭饵,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站梁厉,受9級特大地震影響辜羊,放射性物質發(fā)生泄漏。R本人自食惡果不足惜词顾,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一八秃、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧肉盹,春花似錦昔驱、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至窍蓝,卻和暖如春腋颠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背吓笙。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工淑玫, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人面睛。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓絮蒿,卻偏偏與公主長得像,于是被迫代替她去往敵國和親叁鉴。 傳聞我的和親對象是個殘疾皇子土涝,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

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