__block 關鍵字

在一個 block 裡頭如果使用了在 block 之外的變數,會將這份變數先複製一份再使用,也就是說,在沒有特別宣告的狀況下,對我們目前所在的 block 來說,所有外部的變數都是唯讀,只能讀取,不能變更。至於 block 裡頭用到的 Objective-C 物件,則都會被多 retain 一次。

如果我們想要讓某個 block 可以改動某個外部的變數,我們就要在這個需要可以被 block 改動的變數前面,加上 __block 關鍵字。

像這樣是不合法的程式:

int i = 1;
void (^block)(void) = ^{
    i = i + 1;
};

應該寫成:

__block int i = 1;
void (^block)(void) = ^{
    i = i + 1;
};

__weak 關鍵字

在使用了 block 之後,記憶體管理會變得非常複雜,所以最好是在開啟了 ARC 自動記憶體管理之後再使用 block。不過,即使開啟了 ARC,還是可能會遇到循環 retain 的問題。

由於 block 中用到的 Objective-C 物件都會被多 retain 一次,這邊所指的 Objective-C 物件也包含 self,所以,假使有個物件的 property 是一個block,而這個 block 裡頭又用到了 self,就會遇到循環 retain 而無法釋放記憶體的問題:self 要被釋放才會去釋放這個 property,但是這個 property 作為 block 又 retain 了 self 導致 self 無法被釋放。

下面這段 code 就有循環 retain 的問題:

@interface MyClass : NSObject
- (void)doSomthing;
@property (copy, nonatomic) void (^myBlock)(void);
@end

@implementation MyClass

- (instancetype)init
{
    self = [super init];
    if (self) {
        self.myBlock = ^ {
            [self doSomthing];
        };
    }
    return self;
}
- (void)doSomthing
{
}
@end

如果我們不想讓 self 被 myBlock 給 retain 起來,我們就要把 self 變成 weak reference 再傳入到 block 中。像是改成這樣:

__weak MyClass *weakSelf = self;
self.myBlock = ^ {
    [weakSelf doSomthing];
};

results matching ""

    No results matching ""