In my iOS ARC-enabled code, I need to pass “self” and other objects to a block. More specifically, I need to interact with self and an ASIHTTPRequest object inside the ASIHTTPRequest‘s completionBlock.
_operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(parseServerReply) object:nil];
_request = [ASIHTTPRequest requestWithURL:@"server.address"];
// ...
[_request setCompletionBlock:^{
[self setResponseString:_request.responseString];
[[MyAppDelegate getQueue] addOperation:_operation];
}];
In order to avoid the following warning: Capturing "self" strongly in this block will likely lead to a retain cycle. I have modified my code to add __weak attributes the the objects that are used in the block following this post: Fix warning "Capturing [an object] strongly in this block is likely to lead to a retain cycle" in ARC-enabled code
The resulting code is:
_operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(parseServerReply) object:nil];
_request = [ASIHTTPRequest requestWithURL:@"server.address"];
// ...
__weak NSOperation * operation = _operation;
__weak ASIHTTPRequest * request = _request;
__weak typeof(self) * self_ = self;
[request setCompletionBlock:^{
[self_ setResponseString:request.responseString];
[[MyAppDelegate getQueue] addOperation:operation];
}];
I want to know if this can still lead to retain cycle and memory leaks. If so, is there a way to avoid the leaks?
You don’t need to make everything weak, nor do want to keep referencing a weak object in the block (especially if the block can execute in a different thread).
Think of it this way. When using ARC, objects are reference counted. dealloc is not called on an object until the reference count goes to zero. So, as long as there is one reference around, the object will stay alive.
However, consider two objects that have a strong reference to each other. Neither will dealloc until the other releases its reference.
When you create a block, it captures its environment, and that means it will create strong references to any objects used in the scope of the block.
With that in mind…
The object will not get dealloc until all strong references are released. If you use it in a block, the block automatically creates its own strong reference to make sure the object lives as long as the block lives.
A __weak reference is a level of indirection that gives you access to an object AS LONG AS THE OBJECT LIVES. Basically, if you assign an object to a __weak pointer, that pointer is guaranteed to give you the same object, as long as that object is alive. once the object starts its own dealloc(), it finds all the __weak pointers and sets them to nil.
So, your _weak pointer will always be in one of two states. It points to a valid object as long as the object lives, or it is nil when the object has dealloc. You should never access an object through a weak pointer, because the object could dealloc behind your back, leaving you with a bad pointer.
So, what you want to do it create a __strong reference on the stack, so that the object stays alive as long as you want it.
In your case…
This block obviously holds a strong reference to
self. You probably do not want that. Let’s try to fix it…Hey, we now have a weak
self, but… you are still going to get the same problem. Why? Because _request and _operation are instance variables. If you access an instance variable inside a block, it implicitly creates a strong reference toself.Giving it another go…
Now, you probably should not be using instance variables “in the raw” but that’s a different topic.
With these changes, you have a block that no longer has a strong reference to self, and if
selfdoes truly dealloc, it handles it gracefully.Finally, I wil reiterate, the assignment to strongSelf is necessary to prevent potential problems where the object disappears after checking weakSelf. Specifically…
Now, in this case, the block is part of the request, which is part of
selfso the likelihood thatselfdeallocs is small, but my main point here is to use self to prevent retain cycles, but still always access the object through a strong reference — the weak-strong dance.