簡體   English   中英

可以使用__weak屬性將參數傳遞給塊導致內存泄漏嗎?

[英]Can using __weak attribute to pass parameter to blocks lead to memory leaks?

在我支持iOS ARC的代碼中,我需要將“self”和其他對象傳遞給一個塊。 更具體地說,我需要在ASIHTTPRequestcompletionBlock與self和ASIHTTPRequest對象進行交互。

_operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(parseServerReply) object:nil];
_request = [ASIHTTPRequest requestWithURL:@"server.address"];

// ...

[_request setCompletionBlock:^{
    [self setResponseString:_request.responseString];
    [[MyAppDelegate getQueue] addOperation:_operation];
}];

為了避免以下警告: Capturing "self" strongly in this block will likely lead to a retain cycle 我修改了我的代碼,以便在此帖子后面的塊中使用的對象添加__weak屬性: 修復警告“在此塊中強烈捕獲[一個對象]可能會導致保留周期”在啟用ARC的代碼中

結果代碼是:

_operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(parseServerReply) object:nil];
_request = [ASIHTTPRequest requestWithURL:@"server.address"];

// ...
__weak NSOperation * operation = _operation;
__weak ASIHTTPRequest * request = _request;
__weak typeof(self) * self_ = self;

[request setCompletionBlock:^{
    [self_ setResponseString:request.responseString];
    [[MyAppDelegate getQueue] addOperation:operation];
}];

我想知道這是否仍會導致保留周期和內存泄漏。 如果是這樣,有沒有辦法避免泄漏?

您不需要使所有內容都變弱,也不想繼續引用塊中的弱對象(特別是如果塊可以在不同的線程中執行)。

這樣想吧。 使用ARC時,對象將被引用計數。 在引用計數變為零之前,不會在對象上調用dealloc。 因此,只要有一個引用,對象就會保持活力。

但是,請考慮兩個具有強引用的對象。 在另一個發布其引用之前,它們都不會被釋放。

創建塊時,它會捕獲其環境,這意味着它將創建對塊范圍內使用的任何對象的強引用。

考慮到這一點...

id object = getMeSomeObject();
// <object> is implicitly __strong, and now has a reference.

在釋放所有強引用之前,該對象不會獲得dealloc。 如果在塊中使用它,則塊會自動創建自己的強引用,以確保只要塊存在,對象就會存在。

__weak引用是一個間接級別,使您可以訪問長期作為對象的對象。 基本上,如果將對象分配給__weak指針,則只要該對象處於活動狀態,該指針就可以保證為您提供相同的對象。 一旦對象啟動它自己的dealloc(),它就會找到所有__weak指針並將它們設置為nil。

因此,_weak指針將始終處於兩種狀態之一。 只要對象存在,它就指向一個有效的對象,或者當對象具有dealloc時它指向nil。 永遠不應該通過弱指針訪問一個對象,因為對象可以在你的背后釋放,留下一個壞指針。

所以,你想要做的是在棧上創建一個__strong引用,這樣只要你想要它,對象就會保持活着狀態。

在你的情況下......

[_request setCompletionBlock:^{
    [self setResponseString:_request.responseString];
    [[MyAppDelegate getQueue] addOperation:_operation];
}];

這個區塊顯然對self有很強的借鑒意義。 你可能不希望這樣。 我們試着解決它......

// weakSelf will be "magically" set to nil if <self> deallocs
__weak SelfType *weakSelf = self;
[_request setCompletionBlock:^{
    // If <self> is alive right now, I want to keep it alive while I use it
    // so I need to create a strong reference
    SelfType *strongSelf = weakSelf;
    if (strongSelf) {
        // Ah... <self> is still alive...
        [strongSelf setResponseString:_request.responseString];
        [[MyAppDelegate getQueue] addOperation:_operation];
    } else {
        // Bummer.  <self> dealloc before we could run this code.
    }
}];

嘿,我們現在有一個弱小的self ,但是......你仍然會遇到同樣的問題。 為什么? 因為_request和_operation是實例變量。 如果訪問塊內的實例變量,它會隱式創建對self的強引用。

給它另一個去......

// weakSelf will be "magically" set to nil if <self> deallocs
__weak SelfType *weakSelf = self;
[_request setCompletionBlock:^{
    // If <self> is alive right now, I want to keep it alive while I use it
    // so I need to create a strong reference
    SelfType *strongSelf = weakSelf;
    if (strongSelf) {
        // Ah... <self> is still alive...
        [strongSelf setResponseString:strongSelf->_request.responseString];
        [[MyAppDelegate getQueue] addOperation:strongSelf->_operation];
    } else {
        // Bummer.  <self> dealloc before we could run this code.
    }
}];

現在,您可能不應該在“原始”中使用實例變量,但這是一個不同的主題。

通過這些更改,您將擁有一個不再具有對self的強引用的塊,並且如果self確實是dealloc,則它會優雅地處理它。

最后,我要重申一下,對strongSelf的賦值是必要的,以防止在檢查weakSelf后對象消失的潛在問題。 特別...

if (weakSelf) {
    // Hey, the object exists at the time of the check, but between that check
    // and the very next line, its possible that the object went away.
    // So, to prevent that, you should ALWAYS assign to a temporary strong reference.
    [weakSelf doSomething];
}

strongSelf = weakSelf;
// OK, now IF this object is not nil, it is guaranteed to stay around as long as
// strongSelf lives.

現在,在這種情況下,塊是請求的一部分,它是self一部分,因此self deallocs的可能性很小,但我的主要觀點是使用self來阻止保留周期,但仍然總是通過一個訪問對象強烈的參考 - 弱強的舞蹈。

您生成的代碼是安全的。 閱讀Brad Larson的答案了解具體細節。

暫無
暫無

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

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