簡體   English   中英

iOS阻止和對自我的強/弱引用

[英]iOS blocks and strong/weak references to self

我有一個關於iOS中塊的自我強弱參考的問題。 我知道在塊內引用self的正確方法是在塊外創建一個弱引用,然后在塊內強引用該弱引用,如下所示:

__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^ {
    typeof(self) strongSelf = weakSelf;
    NSLog(@"%@", strongSelf.someProperty);
});

但是,如果你有嵌套塊會發生什么? 一組參考文獻足夠嗎? 或者你需要為每個街區設置一套新套裝? 例如,以下哪項是正確的?

這個:

__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^ {
    typeof(self) strongSelf = weakSelf;
    NSLog(@"%@", strongSelf.someProperty);
    dispatch_async(dispatch_get_main_queue(), ^ {
        strongSelf.view.frame = CGRectZero;
    });
});

或這個:

__weak typeof(self) weakSelf = self;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^ {
        typeof(self) strongSelf = weakSelf;
        NSLog(@"%@", strongSelf.someProperty);
        __weak typeof(strongSelf) weakSelf1 = strongSelf;
        dispatch_async(dispatch_get_main_queue(), ^ {
            typeof(strongSelf) strongSelf1 = weakSelf1;
            strongSelf1.view.frame = CGRectZero;
        });
    });

非常感謝任何信息或解釋!

您不需要制作兩組弱引用。 你想要用塊來避免的是一個保留周期 - 兩個對象讓對方不必要地活着。

如果我有一個具有此屬性的對象:

@property (strong) void(^completionBlock)(void);

我有這個方法:

- (void)doSomething
{
    self.completionBlock = ^{
        [self cleanUp];
    };

    [self doLongRunningTask];
}

當我將它存儲在completionBlock屬性中時,該塊將保持活動狀態。 但是因為它在塊中引用self ,所以塊會保持self活着直到它消失 - 但這不會發生,因為它們都是相互引用的。

在這個方法中:

- (void)doSomething
{
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        [self cleanUp];
    }];

    [self doLongRunningTask];
}

你不需要做一個弱引用self 該塊將保持self活着,因為它從內部引用self ,但由於我們所做的只是將塊移交給[NSOperationQueue mainQueue]self不會使塊保持活動狀態。

希望這可以幫助。

兩種結構都很好。 這取決於你的意圖。 如果對象是(a)在外部塊開始之后釋放但是(b)在內部塊在主隊列上開始之前,你想要發生什么? 如果您不希望它保留在這種情況下(我可能會猜測是您的意圖,假設您首先進行了這個weakSelf ),那么請使用您的最后一個示例,其中您有第二個弱指針。 否則你可以使用你的另一個例子。

話雖如此,有幾點意見:

  1. 你不得不首先使用這種weakSelf模式,這不是一個weakSelf結論。 有些人錯誤地認為他們必須使用這種weakSelf模式來避免強烈的參考周期(也就是保留周期)。 但是這個代碼示例並不構成強大的參考周期。 它只是在調度代碼執行時保留對象,這是一個非常不同的考慮因素。

    事實上,有時你需要/想要那個。 有時候你沒有。 這取決於您正在解決的業務問題。 當然,你經常不希望它對self有強烈的引用,在這種情況下, weakSelf模式非常有意義。 但情況並非總是如此。

    但我的觀點是,你不應該追求這種weakSelf模式(至少在這個dispatch_async場景中)以避免強大的參考周期。 沒有這樣的循環。 這是一個問題,你有一個塊變量(例如一些completionHandler塊)。 在這種情況下, weakSelf模式至關重要。 但不是在這里。

  2. 但是讓我們考慮一下你不希望self保留的情況。 然后是一個問題,你是否希望首先繼續發送代碼。 如果沒有,也許您應該使用具有可取消操作的操作隊列而不是GCD。

    例如,我很驚訝人們在一些后台網絡請求運行時是否經常會保留視圖控制器時會感到痛苦,但是不要擔心他們是否應該首先取消該后台網絡請求。 通常,后者是一個更重要的設計考慮因素(例如,您下載的PDF或圖像占用的視頻控制器將占用更多的系統資源(內存和網絡帶寬))。

  3. 但是我們假設(a)你真的希望調度的代碼繼續執行,但是(b)你不想保留self (這似乎是一個罕見的場景,但它是你所問過的那個,所以讓我們繼續追求。)最后一個問題是你是否需要你的strongSelf構造。 在你的情況下,你只需要調用一個self方法,你不需要打擾這個strongSelf結構。 只有當你要順從ivars或者需要避免競爭條件時,這才是至關重要的。 但是,在這個例子中,假設發送給nil對象的消息什么都不做,你在技術上通常根本不需要擔心這個strongSelf構造。

別誤會我的意思。 讓自己圍繞weakSelf模式,以及有時伴隨它的嵌套strongSelf模式是很好的。 我只是建議理解何時真正需要這些模式。 而且我認為GCD與可取消的NSOperation的選擇往往是一個更為關鍵但卻經常被忽視的問題。

創建塊並將其存儲在堆棧中。 因此,當創建塊的方法返回時,塊將被銷毀。

如果塊成為實例變量ARC,則將塊從堆棧復制到堆。 您可以使用復制消息顯式復制塊。 您的塊現在是基於堆的塊而不是基於堆棧的塊。 而且你必須處理一些內存管理問題。 塊本身將對它引用的任何對象保持強引用。 在塊外部聲明__weak指針,然后在塊內引用此指針以避免保留周期。

暫無
暫無

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

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