1

I have a class which holds a block as an object property:

@property (nonatomic, readwrite, copy) SFFailureBlock failureBlock;

where SFFailureBlock:

typedef void (^SFFailureBlock)(NSError *error);

I have an operation also declared as an object property (AFHTTPRequestOperation) and I want it to call the failure block once it is completed.

    [self.operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
    __weak NSError *error = [NSError errorWithDomain:@"com.test" code:100 userInfo:@{@"description": @"zero results"}];
    failureBlock(error);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"nothing");
}];

I get a compiler warning "Capturing 'self' strongly in this block is likely to lead to a retain cycle". I have searched the internet but I couldn't find a decent solution as to why this leads to a retain cycle. I am not calling 'self' inside the block anywhere.

Another strange thing is that if I write 'self.failureBlock(error)' the compiler does not give me any warning!

Can anyone explain to me what is going on? I must be seriously missing something in ARC memory management rules, but I can't figure it out.

technerd
  • 14,144
  • 10
  • 61
  • 92
csotiriou
  • 5,653
  • 5
  • 36
  • 45

1 Answers1

4

When you refer to "failureBlock" in the operation's block, you are really doing "self-> failureBlock" - so it implicitly retains self. What you can do is create an automatic variable SFFailureBlock xFailureBlock = failureBlock; above the selfoperation, then use it in the block. [Again, you want to avoid any self-> references INSIDE that block either.]

David H
  • 40,852
  • 12
  • 92
  • 138
  • 1
    Unless I'm mistaken, it might also be a good idea to make the xFailureBlock in your example __weak or __unsafe_unretained. – Brad Larson Jul 28 '12 at 02:06
  • I believe but don't know for sure that the xFailure auto var for failure block will copy the block (which is then captured by the enclosing block). – David H Jul 28 '12 at 12:55
  • I see. However, isn't failureblock an instance property of the controller? I thought that in general, when we do something like "[self.myarray addObject:anObject];" inside a block then "myArray" is not retained. Am I wrong? – csotiriou Jul 29 '12 at 15:07
  • In the case you site, self is retained. Its the same as if you used myarray by itself. I posted the same issue on Apple's ObjectiveC listserv, and got this answer: "When you reference an objective-c instance variable in a block, self is closed over, rather than the variable itself. It's as if you had written self->foo = YES; " – David H Jul 29 '12 at 22:32
  • I forgot to mention in the above that it was an Apple engineer who supplied the answer. – David H Jul 30 '12 at 13:10