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?
// 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.