首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

深入淺出 Objective-C Block:捕獲變量的三種行為大解析

     編輯:關於C語言

深入淺出 Objective-C Block:捕獲變量的三種行為大解析

Block 是 Objective-C 中極具威力的特性,許多開發者卻對其捕獲變量的機制感到困惑。本文將剖析 Block 對局部變量、__block 修飾變量、static 變量以及全域變量的四種不同捕獲行為,幫你徹底搞懂 Block 內部的變量世界。

案例一:普通局部變量 —— 捕獲的是「定義那一刻的值」

void test() {
    int age = 10;
    void (^block)() = ^{
        NSLog(@"----age=%d", age); // 輸出 10
    };
    age = 20;
    block();
}

編譯器實際上將 Block 內的 age 直接替換為常數 10。因為局部變量存放在棧上,Block 定義時會將其值「拷貝」一份,後續外部修改 age 與 Block 內部無關。這也是為什麼 Block 捕獲局部變量是安全的——即使變量離開作用域銷毀,Block 仍持有複製的值。

案例二:__block 修飾變量 —— 捕獲的是「變量本身」

void test3() {
    __block int age = 10;
    void (^block)() = ^{
        NSLog(@"----age=%d", age); // 輸出 20
    };
    age = 20;
    block();
}

__block 會將變量包裝在一個結構體中,存放於堆上(或透過 runtime 管理),Block 內部持有指向該結構體的指標。因此 Block 內外共享同一塊記憶體,外部修改值,Block 內部立即可見。這讓 Block 能夠「寫回」外部變量,是實現雙向數據流的關鍵。

案例三:static 靜態變量 —— 捕獲的是「記憶體地址」

void test4() {
    static int age = 10;
    void (^block)() = ^{
        NSLog(@"----age=%d", age); // 輸出 20
    };
    age = 20;
    block();
}

靜態變量存放在全域/靜態區,生命週期贯穿整個程式運行。Block 直接捕獲其記憶體地址,故能即時讀取最新值,行為類似全域變量。

案例四:全域變量 —— 同樣捕獲地址,動態訪問

int num = 10;
void test5() {
    void (^block)() = ^{
        NSLog(@"----num=%d", num); // 輸出 20
    };
    num = 20;
    block();
}

全域變量同樣位於全域區,Block 捕獲其地址,實現動態訪問。

核心判斷邏輯總結

判斷 Block 能否追蹤變量變化,只需問一句:「這個變量會不會馬上銷毀?」

  • 棧上普通局部變量 → 會銷毀 → Block 拷貝值(唯讀)
  • __block 修飾 → 強制延長生命週期 → Block 捕獲引用(可讀寫)
  • static/全域變量 → 永不銷毀 → Block 捕獲地址(動態讀寫)

實戰建議

若需在 Block 內修改外部局部變量,務必加上 __block;若僅需讀取且不希望受外部後續修改影響,直接使用普通局部變量即可,這也是最安全的預設行為。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved