Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
195 views
in Technique[技术] by (71.8m points)

ios - Retain cycle on an Obj-C block using itself

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];
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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];

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...