(四)Block之 __block修飾符及其存儲(chǔ)域

相關(guān)文章


引言

int i = 0; // 不加__block修飾符將編譯錯(cuò)誤
void (^blk)() = ^() {
    i = 1; // error5饫怠<萑佟!F张荨播掷!
};

當(dāng)我們?cè)贐lock語(yǔ)法內(nèi)修改自動(dòng)變量時(shí),沒有加__block修飾符撼班,將會(huì)得到一個(gè)編譯錯(cuò)誤

為了保存Block對(duì)值的操作歧匈,我們可以定義:

  • 全局變量
  • 靜態(tài)全局變量
  • 靜態(tài)局部變量
int global_var = 1; // 全局變量
static int static_global_var = 2; // 靜態(tài)全局變量

{
      static int static_var = 3; // 靜態(tài)局部變量
      void (^blk)() = ^() {
            global_var++;
            static_global_var++;
            static_var++;
            printf("%d\n", global_var); // 輸出2
            printf("%d\n", static_global_var); // 輸出3
            printf("%d\n", static_var); // 輸出4
        };
        blk();
}

輸出結(jié)果如我們所愿,值修改成功了

我們進(jìn)行編碼轉(zhuǎn)換砰嘁,看下發(fā)生了什么事情

int global_var = 1;
static int static_global_var = 2;

/ * Block結(jié)構(gòu)體 */
struct __main_block_impl_0 { 
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  int *static_var;
 // ......省略構(gòu)造函數(shù)
};
/ * Block方法 */
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  int *static_var = __cself->static_var;  // 注意這里<!0妗U迕帷!

      global_var++;
      static_global_var++;
      (*static_var)++;  // 注意這里C逖簟?纳摺!J臁秀撇!
      printf("%d\n", global_var);
      printf("%d\n", static_global_var);
      printf("%d\n", (*static_var));
}

可見,對(duì)全局變量靜態(tài)全局變量的訪問依然不作變化向族,靜態(tài)局部變量則使用指針對(duì)其訪問(其指針傳遞給__main_block_impl_0Block結(jié)構(gòu)體呵燕,通過(guò)保存的指針在Block語(yǔ)法內(nèi)來(lái)訪問自動(dòng)變量)

我們也可以給變量加上__block修飾符,達(dá)到同樣的目的

__block修飾符

__block int i = 10; // 不加__block修飾符將編譯錯(cuò)誤
void (^blk)() = ^() {
   i = 20;
};

添加__block修飾符后件相,如愿達(dá)到了目的再扭,接下來(lái)看看發(fā)生了什么事情

struct __Block_byref_i_0 {
  void *__isa;
 __Block_byref_i_0 *__forwarding; // 注意這里Q醪浴!7悍丁:蛞!
 int __flags;
 int __size;
 int i;
};

/ * Block結(jié)構(gòu)體 */
struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  __Block_byref_i_0 *i; // 注意這里6氐!9淇D!
構(gòu)造函數(shù)
__main_block_impl_0(void *fp, 
                    struct __main_block_desc_0 *desc, 
                  __Block_byref_i_0 *_i,
                  int flags=0) : i(_i->__forwarding) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
/ * Block方法 */
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
      __Block_byref_i_0 *i = __cself->i; // 注意這里1缁>宓选!3研埂患整!
     (i->__forwarding->i) = 20;// 注意這里!E缰凇8餮琛!到千!
}

/ * __block int i = 0; 轉(zhuǎn)換后代碼*/
__Block_byref_i_0 i = {0, //__isa
                      (__Block_byref_i_0 *)&i,  // __forwarding 注意這里2场!c舅摹膀息!
                      0,  // flag
                      sizeof(__Block_byref_i_0), // size
                      10 // 變量i
};

  • 添加__block修飾符后, 代碼量增加了不少,自動(dòng)變量i被轉(zhuǎn)換成了結(jié)構(gòu)體__Block_byref_i_0了赵,值被保存在了這個(gè)結(jié)構(gòu)體內(nèi)部
  • 和上面的對(duì)靜態(tài)自動(dòng)變量賦值(*static_var)++;潜支,使用指向改變量的指針不同,__block的賦值操作變成了(i->__forwarding->i) = 20;
  • 從代碼轉(zhuǎn)換結(jié)果看__Block_byref_i_0 i變量的初始化柿汛,__forwarding被賦值(__Block_byref_i_0 *)&i,冗酿,也就是__forwarding指針間接訪問,這個(gè)指針指向自身苛茂,如下圖所示
    __main_block_impl_0

    那么已烤,為什么會(huì)有__forwarding呢? 下面將作出解釋

__block變量存儲(chǔ)域

已知妓羊,使用了__block變量的Block從棧復(fù)制到堆時(shí)胯究,__block變量也會(huì)受到影響,總結(jié)如下

__block變量存儲(chǔ)域 Block從棧復(fù)制到堆
從棧復(fù)制到堆并被Block持有
被Block持有
  • 當(dāng)棧上的Block被復(fù)制到堆上時(shí)躁绸,__block變量也會(huì)隨之復(fù)制裕循,并且Block持有該變量
單個(gè)Block使用__block變量
  • 多個(gè)Block中使用__block變量時(shí)臣嚣,任何一個(gè)Block被復(fù)制到堆時(shí),__block變量也會(huì)一并復(fù)制到堆并被持有剥哑,其余Block被復(fù)制時(shí)硅则,僅需要__block 變量的引用計(jì)數(shù)
多個(gè)Block中使用__block變量
  • 和使用引用計(jì)數(shù)一樣,在堆上的Block被廢棄株婴,它所引用的__block變量將被釋放
廢棄Block

理解Block作用域之后怎虫,我們發(fā)現(xiàn)這和OC引用計(jì)數(shù)方式管理方式一樣,使用__block修飾符來(lái)持有對(duì)象困介,當(dāng)Block被廢棄之后大审,__block修飾變量也隨之釋放

當(dāng)Block被復(fù)制到堆之后,會(huì)將自身的__forwarding指針更新座哩,依然指向“最新”的自己徒扶,這樣就保證了在棧上或者堆上都能正確訪問對(duì)應(yīng)變量

復(fù)制之后

__forwarding指針的作用正在這里,上文的

 __Block_byref_i_0 *i = __cself->i; 
(i->__forwarding->i) = 20;
  • 當(dāng)Block處于棧時(shí)根穷,__forwarding指向自身姜骡,i->__forwarding->i訪問的是棧上的結(jié)構(gòu)體的變量i
  • 當(dāng)Block被復(fù)制到堆時(shí),i->__forwarding->i訪問的是堆上的結(jié)構(gòu)體的變量i

由此

__forwarding 保證在棧上或者堆上都能正確訪問對(duì)應(yīng)變量

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末屿良,一起剝皮案震驚了整個(gè)濱河市圈澈,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌尘惧,老刑警劉巖士败,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異褥伴,居然都是意外死亡谅将,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門重慢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)饥臂,“玉大人,你說(shuō)我怎么就攤上這事似踱∮缥酰” “怎么了?”我有些...
    開封第一講書人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵核芽,是天一觀的道長(zhǎng)囚戚。 經(jīng)常有香客問我,道長(zhǎng)轧简,這世上最難降的妖魔是什么驰坊? 我笑而不...
    開封第一講書人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮哮独,結(jié)果婚禮上拳芙,老公的妹妹穿的比我還像新娘察藐。我一直安慰自己,他們只是感情好舟扎,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開白布分飞。 她就那樣靜靜地躺著,像睡著了一般睹限。 火紅的嫁衣襯著肌膚如雪譬猫。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,462評(píng)論 1 302
  • 那天羡疗,我揣著相機(jī)與錄音删窒,去河邊找鬼。 笑死顺囊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蕉拢。 我是一名探鬼主播特碳,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼晕换!你這毒婦竟也來(lái)了午乓?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤闸准,失蹤者是張志新(化名)和其女友劉穎益愈,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體夷家,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蒸其,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年催式,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了胶逢。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片彩届。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡再膳,死狀恐怖坷襟,靈堂內(nèi)的尸體忽然破棺而出构蹬,到底是詐尸還是另有隱情溃蔫,我是刑警寧澤皆疹,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布闽铐,位于F島的核電站蝶怔,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏兄墅。R本人自食惡果不足惜踢星,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望隙咸。 院中可真熱鬧斩狱,春花似錦耳高、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至秕岛,卻和暖如春碌燕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背继薛。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工修壕, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人遏考。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓慈鸠,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親灌具。 傳聞我的和親對(duì)象是個(gè)殘疾皇子青团,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

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