簡體   English   中英

我應該在嵌套塊中使用weakSelf嗎?

[英]Should I use weakSelf in nested blocks?

我正在嘗試正確避免在Objective C中使用塊保留循環,並且我不確定是否有嵌套塊。

如果我寫一個這樣的簡單塊:

[self doSomethingWithBlock:^{
    [self doSomethingElse];
}];

編譯器捕獲並警告我這可能導致保留周期。 我按如下方式更改它以避免循環:

__weak __typeof(self)weakSelf = self;
[self doSomethingWithBlock:^{
    __strong __typeof(weakSelf)strongSelf = weakSelf;
    [strongSelf doSomethingElse];
}];

當我寫這樣的東西時:

[self doSomethingWithBlock:^(MyObject* object){
    [object doSomethingElseWithBlock:^{
        [self doYetAnotherThing];
    }];
}];

編譯器很高興,但我不相信它是安全的。 盡管介於兩者之間存在中間object ,但它在概念上看起來仍然與上面相同,但現在它是一個有3個保留的循環。

應該是這樣嗎?

[self doSomethingWithBlock:^(MyObject* object){
    __weak __typeof(self)weakSelf = self;
    [object doSomethingElseWithBlock:^{
        __strong __typeof(weakSelf)strongSelf = weakSelf;
        [strongSelf doYetAnotherThing];
    }];
}];

或者像這樣?

__weak __typeof(self)weakSelf = self;
[self doSomethingWithBlock:^(MyObject* object){
    [object doSomethingElseWithBlock:^{
        __strong __typeof(weakSelf)strongSelf = weakSelf;
        [strongSelf doYetAnotherThing];
    }];
}];

在這種情況下,您不必擔心循環引用。 你擔心的是一個實際上不再需要對象self的情況,但是在嵌套塊中使用self會讓它不必要地活着。 例如,如果您的視圖控制器在屏幕移除視圖時應該消失,但您下載了要在控制器視圖中顯示的圖像。 如果圖像在視圖已經消失后很長時間到達,則不希望視圖控制器再次存在。

最好的是

__weak typeof (self) weakSelf = self;

在調用最外層方法之前。 然后在每個應該使用self的塊中添加

typeof (self) strongSelf = weakSelf;

並在該塊中使用strongSelf。 根據具體情況,你可能想檢查那時strongSelf不是nil,但是當它為nil時發送消息給strongSelf沒有任何效果,所以如果你只是發送消息並獲取或設置屬性,那么檢查沒有必要。

如果你不這樣做會怎么樣? 不同之處在於,如果你在任何地方(或者只是在最里面的塊中)使用self,那么self可以不必要地保持在最里面的塊中。

看看這個問題的答案。

我會這樣做的

__weak typeof (self) weakSelf = self;
[self doSomethingWithBlock:^(MyObject* object){
    [object doSomethingElseWithBlock:^{
        [weakSelf doYetAnotherThing];
    }];
}];

Xcode 8 beta 4強調了self關鍵字,並警告了在塊內部使用它的可能保留周期。

每個Apple Developer Connection的Objective-C編程(使用塊):

捕獲自身時避免強引用周期如果需要在塊中捕獲self,例如在定義回調塊時,考慮內存管理含義非常重要。

塊保持對任何捕獲對象(包括self)的強引用,這意味着,例如,如果對象維護捕獲self的塊的copy屬性,則很容易以強引用循環結束:

@interface XYZBlockKeeper : NSObject
@property (copy) void (^block)(void);
@end
@implementation XYZBlockKeeper
- (void)configureBlock {
    self.block = ^{
        [self doSomething];    // capturing a strong reference to self
                               // creates a strong reference cycle
    };
}
...
@end

編譯器會警告您這樣一個簡單的示例,但更復雜的示例可能涉及對象之間的多個強引用以創建循環,從而使診斷更加困難。

為了避免這個問題,最好的做法是捕獲對self的弱引用,如下所示:

- (void)configureBlock {
    XYZBlockKeeper * __weak weakSelf = self;
    self.block = ^{
        [weakSelf doSomething];   // capture the weak reference
                                  // to avoid the reference cycle
    }
}

通過捕獲指向self的弱指針,該塊將不會與XYZBlockKeeper對象保持強關系。 如果在調用塊之前釋放該對象,則weakSelf指針將簡單地設置為nil。

據報道,該站點提供了一種方法,可以在塊內部使用self關鍵字時使其變弱; 它還提供了返回弱自我或類對象的指令,這些對象以前是強大的,強大的:

https://coderwall.com/p/vaj4tg/making-all-self-references-in-blocks-weak-by-default

你不應該僅僅因為你從編譯器收到警告而捕獲一些東西; 編譯器警告只是猜測; 它不知道你調用的方法是如何引用的。 只有在了解了引用的體系結構並確定存在循環並確定捕獲弱引用時仍然保留預期行為時,才應執行此操作。 你還沒有向我們展示-doSomethingWithBlock:的代碼-doSomethingWithBlock: 它只會在該方法內部創建一個保留周期,它將塊分配給self的屬性或實例變量。 它會這樣做嗎? 如果沒有,則沒有保留周期,並且外部塊無法self捕獲。

假設self弱捕獲的外部塊是正確的,外部塊強烈捕獲self的示例是不可能的。 剩下的問題是內部塊是否應該強烈地捕獲self (或任何self版本,例如strongSelf ,是合適的)。 換句話說,你是否會這樣做:

__weak __typeof(self) weakSelf = self;
[self doSomethingWithBlock:^(MyObject* object){
    __strong __typeof(weakSelf) strongSelf = weakSelf;
    if (strongSelf) {
        [object doSomethingElseWithBlock:^{
            [strongSelf doYetAnotherThing];
        }];
    }
}];

或類似的東西:

__weak __typeof(self) weakSelf = self;
[self doSomethingWithBlock:^(MyObject* object){
    __strong __typeof(weakSelf) strongSelf = weakSelf;
    if (strongSelf) {
        [object doSomethingElseWithBlock:^{
            __strong __typeof(weakSelf) strongSelf = weakSelf;
            if (strongSelf) {
                [strongSelf doYetAnotherThing];
            }
        }];
    }
}];

同樣,要確定的主要問題是,如果內部塊強烈地捕獲self是否存在保留周期。 如果[object doSomethingElseWithBlock:...以某種方式將塊分配給self的屬性或實例變量,那么只會有一個保留周期。 但怎么可能呢? 該方法在objectobject ,而不是self 該方法不會以任何方式獲得self 除非存在復雜的事情,否則該方法不會分配給self的屬性或實例變量,因此不太可能創建保留周期。 這意味着內部塊self弱捕獲對於防止保留周期不是必需的。

但是內部區塊是否會self弱或強烈地捕獲可能會影響行為。 也就是說,如果內部塊self捕獲弱,則可以在塊運行時釋放self ,在這種情況下[strongSelf doYetAnotherThing]; 不會被執行,而如果內部區塊強烈地self捕獲,它將保持self活着和[strongSelf doYetAnotherThing]; 將被執行。 所以它取決於-doYetAnotherThing作用。 如果它在self上執行某些UI操作(UI視圖或其他內容),那么無論是在不再顯示的視圖上執行它都不會產生影響。 但是,如果它例如向網絡發送某些東西,那么它是否被執行可以產生很大的不同。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM