Search code examples
objective-cautomatic-ref-countingasihttprequestobjective-c-blocksgrand-central-dispatch

Objective C ASIHTTPRequest nested GCD block in complete block


I was wondering if this is the correct way to have nested blocks working on the same variable in Objective C without causing any memory problems or crashes with ARC. It starts with a ASIHttpRequest complete block.

MyObject *object = [dataSet objectAtIndex:i];

ASIHTTPRequest *request = [[ASIHTTPRequest alloc]initWithURL:@"FOO"];

__block MyObject *mutableObject = object;

[request setCompleteBlock:^{

      mutableObject.data = request.responseData;

      __block MyObject *gcdMutableObject = mutableObject;

      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{

              [gcdMutableObject doLongComputation];

              dispatch_async(dispatch_get_main_queue(),^{

                     [self updateGUIWithObject:gcdMutableObject];
              }); 

      });

[request startAsynchronous];

My main concern is nesting the dispatch queues and using the __block version of the previous queue to access data. Is what I am doing safe?


Solution

  • // Under ARC the blocks will automatically retain <object>
    MyObject *object = [dataSet objectAtIndex:i];
    ASIHTTPRequest *request = [[ASIHTTPRequest alloc]initWithURL:@"FOO"];
    __weak ASIHTTPRequest *weakRequest = request;                        // EDIT
    [request setCompleteBlock:^{
        // <object> is retained by the block.
        // Changing a property of <object> but not <object> itself.
        ASIHTTPRequest *request = weakRequest;                           // EDIT
        if (!request) return;                                            // EDIT
        object.data = request.responseData;    
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{
            // <object> retained by this block too...
            [object doLongComputation];
            dispatch_async(dispatch_get_main_queue(),^{
                // <object> retained by this block too
                // Note, <self> is also retained...
                // Use the same "weak" trick if you don't want this      // EDIT
                [self updateGUIWithObject:object];
            });
        });
    }];
    [request startAsynchronous];
    

    EDIT

    endy does bring up a valid point (though using __usnafe_unretained should be generally avoided. While I did originally note that both request and self are retained in the original post, I assumed appropriate measures would be taken as necessary. That was not a wrong decision on my part.

    So, there are several ways to break the retain cycle for this request, but using a weak reference is probably the safest and best choice here.

    See the lines marked with // EDIT in the above code.