2011年11月7日 星期一

Automatic Reference Counting (ARC) 3

__block 的使用方法

特定將 __block 獨立一篇,主要是因為它的用法我還不是很確定
目前先以所理解的範圍內寫下來,爾後有可能再修改
__block id x;
保留 x 變數值,直到 x 被設定為 nil
使用情況可能會在於 Block 區塊內

如官方範例

__block MyViewController *myController = [[MyViewController alloc] init…];
// ...
myController.completionHandler = ^(NSInteger result) {
[myController dismissViewControllerAnimated:YES completion:nil];
myController = nil; // 記得要設成 nil 才能解除被 block 住的限制
};

completionHandler 被指定了一個區塊,裡面有使用 myController 的變數
但這個區塊不知道何時會被使用,所以無法確定 myController 的生存週期該如何設定
此時就使用 __block 標記保留生存週期,直到該變數被設定成 nil

__block 有別於 __strong、__weak 等標記,是一個獨立的標記
所以也可以
__unsafe_unretained __block id x;.
這樣子使用
這表示該 x 不會被保留,在 x 被釋放後,也不會自動設成 nil
當然,官方是不鼓勵這樣子寫

如果需要不保留物件時,官方建議使用 __weak
以下是官方範例

MyViewController *myController = [[MyViewController alloc] init…];
// ...
__weak MyViewController *weakMyController = myController;
myController.completionHandler = ^(NSInteger result) {
MyViewController *strongMyController = weakMyController;
if (strongMyController) {
// ...
[strongMyController dismissViewControllerAnimated:YES completion:nil];
// ...
}
else {
// Probably nothing...
}
};

在 Block 區塊裡用一個 strongMyController 變數保留起來,再判斷該變數是不是 nil
避免跑一半時,weakMyController 變成 nil,程式就死掉了

這邊特別加註

若是 Block 區域裡的變數沒有被註記成 __block 時,它會是複製一份

例:
 int a = 10;

myController.completionHandler = ^(NSInteger result) {
 NSLog(@"a = %d", a); // 當它執行時,會是 10
}

a = 20;

but

__block int a = 10;

myController.completionHandler = ^(NSInteger result) {
 NSLog(@"a = %d", a); // 當它執行時,會是 20
}

a = 20;

沒有留言:

張貼留言