簡體   English   中英

在ARC中總是將自我的弱引用傳遞給塊?

[英]Always pass weak reference of self into block in ARC?

我對Objective-C中的塊使用有點困惑。 我目前使用ARC,我的應用程序中有很多塊,目前總是指self而不是弱引用。 這可能是導致這些障礙保留self並防止其被解除分配的原因嗎? 問題是,我是否應該總是在一個區塊中使用selfweak引用?

-(void)handleNewerData:(NSArray *)arr
{
    ProcessOperation *operation =
    [[ProcessOperation alloc] initWithDataToProcess:arr
                                         completion:^(NSMutableArray *rows) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [self updateFeed:arr rows:rows];
        });
    }];
    [dataProcessQueue addOperation:operation];
}

ProcessOperation.h

@interface ProcessOperation : NSOperation
{
    NSMutableArray *dataArr;
    NSMutableArray *rowHeightsArr;
    void (^callback)(NSMutableArray *rows);
}

ProcessOperation.m

-(id)initWithDataToProcess:(NSArray *)data completion:(void (^)(NSMutableArray *rows))cb{

    if(self =[super init]){
        dataArr = [NSMutableArray arrayWithArray:data];
        rowHeightsArr = [NSMutableArray new];
        callback = cb;
    }
    return self;
}

- (void)main {
    @autoreleasepool {
        ...
        callback(rowHeightsArr);
    }
}

這不僅有助於把重點放在strongweak的討論的一部分。 而是專注於循環部分。

保留周期是當對象A保留對象B時發生的循環, 對象B保留對象A.在這種情況下,如果釋放了任一對象:

  • 對象A不會被釋放,因為對象B保存對它的引用。
  • 但是只要對象A具有對它的引用,對象B就不會被釋放。
  • 但是對象A永遠不會被釋放,因為對象B擁有對它的引用。
  • 無限的

因此,這兩個對象只會在程序的生命周期中閑逛,即使它們應該在一切正常工作的情況下被解除分配。

所以,我們擔心的是保留周期 ,並且沒有關於創建這些周期的塊本身。 這不是問題,例如:

[myArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
   [self doSomethingWithObject:obj];
}];

該塊保留self ,但self不保留該塊。 如果釋放了一個或另一個,則不會創建任何循環,並且所有內容都會被取消分配。

你遇到麻煩的地方是這樣的:

//In the interface:
@property (strong) void(^myBlock)(id obj, NSUInteger idx, BOOL *stop);

//In the implementation:
[self setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) {
  [self doSomethingWithObj:obj];     
}];

現在,您的對象( self )具有對塊的明確strong引用。 該塊具有對self隱含強烈引用。 這是一個循環,現在這兩個對象都不會被正確釋放。

因為,在這樣的情況下, self 定義已經具有對塊的strong引用,通常通過對塊使用明確弱的self引用來解決它:

__weak MyObject *weakSelf = self;
[self setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) {
  [weakSelf doSomethingWithObj:obj];     
}];

但這不應該是你在處理調用self塊時遵循的默認模式 這應該僅用於打破自我和塊之間的保留周期。 如果你在任何地方采用這種模式,那么你就有可能將一個塊傳遞給在取消分配self之后執行的東西。

//SUSPICIOUS EXAMPLE:
__weak MyObject *weakSelf = self;
[[SomeOtherObject alloc] initWithCompletion:^{
  //By the time this gets called, "weakSelf" might be nil because it's not retained!
  [weakSelf doSomething];
}];

您不必總是使用弱引用。 如果您的塊未被保留,但已執行然后被丟棄,則您可以強烈捕獲自身,因為它不會創建保留周期。 在某些情況下,您甚至希望塊保持自身直到塊完成,因此它不會過早釋放。 但是,如果您強烈捕獲塊,並且在捕獲自身內部,則會創建一個保留周期。

我完全贊同@jemmons。

“但這不應該是你在處理調用self的塊時所遵循的默認模式!這應該僅用於打破自我和塊之間的保留周期。如果你在各處采用這種模式,你就是' d冒着將一個塊傳遞給自我被解除分配后執行的東西的風險。“

//SUSPICIOUS EXAMPLE:
__weak MyObject *weakSelf = self;
[[SomeOtherObject alloc] initWithCompletion:^{
  //By the time this gets called, "weakSelf" might be nil because it's not  retained!
  [weakSelf doSomething];
}];

為了解決這個問題,我們可以在塊內的weakSelf上定義一個強引用。

__weak MyObject *weakSelf = self;
[[SomeOtherObject alloc] initWithCompletion:^{
   MyObject *strongSelf = weakSelf;
  [strongSelf doSomething];
}];

正如Leo指出的那樣,您添加到問題中的代碼不會建議強大的參考周期(也就是保留周期)。 可能導致強引用周期的一個與操作相關的問題是,如果操作未被釋放。 雖然你的代碼片段表明你沒有將你的操作定義為並發,但是如果你有,那么如果你從未發布過isFinished ,或者如果你有循環依賴關系,或者類似的東西,它就不會被釋放。 如果未釋放操作,則視圖控制器也不會被釋放。 我建議在你的操作的dealloc方法中添加一個斷點或NSLog ,並確認它已被調用。

你說:

我理解保留周期的概念,但我不太清楚塊中會發生什么,所以這讓我有點困惑

塊發生的保留周期(強參考周期)問題就像您熟悉的保留周期問題一樣。 塊將保持對塊中出現的任何對象的強引用,並且在塊本身釋放之前不會釋放那些強引用。 因此,如果塊引用self ,或者甚至只引用self的實例變量,那將保持對self的強引用,直到塊被釋放時才解析(或者在這種情況下,直到釋放NSOperation子類)。

有關更多信息,請參閱“ 使用Objective-C:使用塊編程”文檔中的“ 捕獲自身時避免強引用循環”部分。

如果您的視圖控制器仍未發布,您只需確定未解析的強引用所在的位置(假設您確認NSOperation已取消分配)。 一個常見的例子是使用重復的NSTimer 或者某些自定義delegate或其他錯誤維護strong引用的對象。 您通常可以使用Instruments來追蹤對象獲得強引用的位置,例如:

在Xcode 6中記錄引用計數

或者在Xcode 5中:

在Xcode 5中記錄引用計數

一些解釋忽略了關於保留周期的條件[如果一組對象通過一系列強關系連接,即使沒有來自組外的強引用,它們也會保持活着。]有關更多信息,請閱讀文檔

這是你如何在塊內使用self:

//調用塊

 NSString *returnedText= checkIfOutsideMethodIsCalled(self);

NSString* (^checkIfOutsideMethodIsCalled)(*)=^NSString*(id obj)
{
             [obj MethodNameYouWantToCall]; // this is how it will call the object 
            return @"Called";


};

暫無
暫無

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

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