I have been using blocks for some time, but I feel that there are things that I am missing due to memory management in both ARC and non-ARC environments. I feel that a deeper understanding will make me lose many memory leaks.
AFNetworking is my main use of Blocks in a particular application. In most cases, inside the operation completion handler, I do something like "[self.myArray addObject]".
In environments with ARC support and without ARC, "self" will be retained in accordance with this article from Apple .
This means that whenever the AFNetworking network operation completion block is called, self is stored inside this block and freed when this block goes out of scope. I believe this applies to both ARC and non-ARC. I ran the Leaks tool and the Static Analyzer tool to find memory leaks. No one showed.
However, only recently I came across a warning that I could not understand. I am using ARC in this particular example.
I have two instance variables that indicate the completion and failure of a network operation.
@property (nonatomic, readwrite, copy) SFCompletionBlock completionBlock; @property (nonatomic, readwrite, copy) SFFailureBlock failureBlock; @synthesize failureBlock = _failureBlock; @synthesize operation = _operation;
Somewhere in the code, I am doing this:
[self.operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { NSError *error = [NSError errorWithDomain:@"com.test" code:100 userInfo:@{@"description": @"zero results"}]; _failureBlock(error); } failure:^(AFHTTPRequestOperation *operation, NSError *error) { NSLog(@"nothing"); }];
Xcode complains about the line that causes failBlock, because the message "Capturing" self "strongly" in this block can lead to a save loop. I believe Xcode is right: the failure block retains self, and self holds its own copy of the block, so none of them will be freed.
However, I have the following questions / observations.
1) If I change _failureBlock (error) to "self.failureBlock (error)" (without quotes), the compiler stops complaining. Why is this? Is this a memory leak that the compiler is missing?
2) In general, what is the best way to work with blocks in environments with ARC support and without ARC when using blocks that are instance variables ? It seems that in the case of AFNetworking termination and failure blocks, these two blocks are not instance variables, so they probably do not fall into the category of retention cycles described above. But when using progress blocks in AFNetworking, what can be done to avoid saving loops like the ones above?
I would like to hear other people's thoughts on ARC and non-ARC with blocks and problems / solutions with memory management. I find these situations error-prone, and I feel that a discussion of this is necessary in order to clarify the situation.
I don't know if this matters, but I am using Xcode 4.4 with the latest LLVM.