Retain cycle on an Obj-C block using itself

风流意气都作罢 提交于 2019-12-12 01:04:24

问题


I have a block to use as a completionHandler for an NSURLConnection asynchronous request whose main job is to spawn a new asynchronous request using the same block for the new requests completion handler. I am doing this because it effectively solves another problem which is to line up a sequence of asynchronous calls and have them fired off in the background. This is working marvelously for us, but we have a warning I am concerned about. Namely, XCode thinks I have a retain cycle. Perhaps I do, I don't know. I've been trying to learn about blocks over the last couple hours but I haven't found an explanation for recursive uses like mine. The warning states `Block will be retained by the captured object'.

My best guess so far is that a retain cycle is exactly what we want, and that to clear when we are done, we just nillify the block variable, which I'm doing. It doesn't get rid of the error, but I don't mind as long as I'm not leaking memory or doing some black magic I'm not aware of. Can anyone address this? Am I handling it right? If not, what should I be doing?

void (^ __block handler)(NSURLResponse *, NSData *, NSError*);
handler = ^(NSURLResponse *response, NSData *data, NSError *error)
{
    [dataArray addObject:data];

    if (++currentRequestIndex < [requestsArray count])
    {

        if (error)
        {
            [delegate requestsProcessWithIdentifier:_identifier processStoppedOnRequestNumber:currentRequestIndex-1 withError:error];
            return;
        }

        [delegate requestsProcessWithIdentifier:_identifier completedRequestNumber:currentRequestIndex-1]; // completed previous request

        [NSURLConnection sendAsynchronousRequest:[requestsArray objectAtIndex:currentRequestIndex]
                                           queue:[NSOperationQueue mainQueue]
                               completionHandler:handler]; // HERE IS THE WARNING
    }
    else
    {
        [delegate requestsProcessWithIdentifier:_identifier completedWithData:dataArray];
        handler = nil;
    }
};
[NSURLConnection sendAsynchronousRequest:[requestsArray objectAtIndex:0]
                                   queue:[NSOperationQueue mainQueue]
                       completionHandler:handler];

回答1:


Try to store your handler block into an instance variable of your view controller (or whatever class you're in).

Assuming that you declare an instance variable named _hander:

{
  void (^_handler)(NSURLResponse *, NSData *, NSError*);
}

Change your code to:

__weak __typeof(&*self)weakSelf = self;
_handler = ^(NSURLResponse *response, NSData *data, NSError *error)
{
  [dataArray addObject:data];

  if (++currentRequestIndex < [requestsArray count])
  {

    if (error)
    {
      [delegate requestsProcessWithIdentifier:_identifier processStoppedOnRequestNumber:currentRequestIndex-1 withError:error];
      return;
    }

    [delegate requestsProcessWithIdentifier:_identifier completedRequestNumber:currentRequestIndex-1]; // completed previous request

    __strong __typeof(&*self)strongSelf = weakSelf;
    [NSURLConnection sendAsynchronousRequest:[requestsArray objectAtIndex:currentRequestIndex]
                                       queue:[NSOperationQueue mainQueue]
                           completionHandler:strongSelf->_handler];
  }
  else
  {
    [delegate requestsProcessWithIdentifier:_identifier completedWithData:dataArray];
  }
};

[NSURLConnection sendAsynchronousRequest:[requestsArray objectAtIndex:0]
                                   queue:[NSOperationQueue mainQueue]
                       completionHandler:_handler];



回答2:


void (^handler)(NSURLResponse *, NSData *, NSError*);
typeof(handler) __block __weak weakHandler;
weakHandler = handler = ^(NSURLResponse *response, NSData *data, NSError *error)
{
    [dataArray addObject:data];

    if (++currentRequestIndex < [requestsArray count])
    {

        if (error)
        {
            [delegate requestsProcessWithIdentifier:_identifier processStoppedOnRequestNumber:currentRequestIndex-1 withError:error];
            return;
        }

        [delegate requestsProcessWithIdentifier:_identifier completedRequestNumber:currentRequestIndex-1]; // completed previous request

        [NSURLConnection sendAsynchronousRequest:[requestsArray objectAtIndex:currentRequestIndex]
                                           queue:[NSOperationQueue mainQueue]
                               completionHandler:weakHandler]; // HERE IS THE WARNING
    }
    else
    {
        [delegate requestsProcessWithIdentifier:_identifier completedWithData:dataArray];
    }
};


来源:https://stackoverflow.com/questions/16725936/retain-cycle-on-an-obj-c-block-using-itself

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!