而且原本在這篇就要講的有關記憶體的問題,
我選擇了往後擱著
我們來先探討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的記憶體管理
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