2011年8月29日 星期一

探討Objective-C Block (part 2)

原本只打算寫兩篇的,但是忽然覺得很多東西可以講。
而且原本在這篇就要講的有關記憶體的問題,
我選擇了往後擱著
我們來先探討block variable,也就是__block這個修飾字。

前一篇有提到,block在別的語言叫做closure,
這個closure的概念很像是把環境閉鎖起來,
而這個環境就是指定義該block的這個call stack frame。
當block被呼叫block_copy的時候,或是[someBlock copy]的時候
這個block就會進入heap,
並且會指到目前的stack frame形成closure。
而block variable會跟這個closure綁住,
所以可能說closure variable會更加的貼切。

我們來看下面一個有趣的例子
typedef NSUInteger (^countdown_type)(void);
countdown_type createCountdown(NSUInteger number)
{
    __block NSUInteger counter = number;
   
    return [[^NSUInteger{
        return counter--;
    } copy] autorelease];
}
這個function產生了一個block,這個block中有一個block variable,
起始值是由傳進來的參數決定。
之後每呼叫一次counter都會減1,並且把原本的值傳回去。
下面使用的範例
countdown = createCountdown(10);
    NSLog(@"%d", countdown()); //10
    NSLog(@"%d", countdown()); //9
    NSLog(@"%d", countdown()); //8

所以我們更能清楚知道local variable跟block variable的差異。
local variable隨著function回傳而該變數的位置就隨著call stack pop掉。
而如果local static variable跟block variable的比較
static local整個app只有一份。
但是block variable是一個closure一份,
所以以這個例子,如果我們用的是local static,則所有的countdown都共用一個counter。
而如果是用block variable,則每個block都各自有自己的一份。

如果你比較瞭解了block variable的定義,
你可以在回頭想想為什麼在block中local variable只能當常數使用,
而block variable可以當變數使用。
相信你心中已經有答案了 :D

探討Objective-C Block (part 1) - block的使用
探討Objective-C Block (part 2) - block變數
探討Objective-C Block (part 3) - block的記憶體管理

1 則留言:

  1. countdown_type countdown1 = createCountdown(10);
    countdown_type countdown2 = createCountdown(100);
    //从打印了的结果来看 createCountdown函数中的__block NSUInteger counter变量与local static不同, 因为local static变量始终是一个,而从下面结果来看是每个block都生成一个counter变量
    //所以我觉得可以认为__block修饰的基本类型变量是存放在block中的, 但是包含它的函数引用了它的内存地址, 这样在函数中也可以修改该变量的值
    NSLog(@"%d", countdown1()); //10
    NSLog(@"%d", countdown2()); //100
    NSLog(@"%d", countdown1()); //9
    NSLog(@"%d", countdown2()); //99
    NSLog(@"%d", countdown1()); //8
    NSLog(@"%d", countdown2()); //98

    回覆刪除