3
votes

So I was reading How do I avoid capturing self in blocks when implementing an API? about how memory management works in regards to referencing self within a completion block and that got me thinking: will the following cause a retain cycle?

Pseudocode:

[AFnetworking requestGet:@"http://www.website.com" completionBlock:(^)(RequestObj* request, NSError* error){
      [self.tableView reloadData];
}];

Ignoring syntax problems, does self.tableView cause a retain cycle? Is it necessary to do the following instead?

__weak id weakSelf = self;
[AFnetworking requestGet:@"http://www.website.com" completionBlock:(^)(RequestObj* request, NSError* error){
      [weakSelf.tableView reloadData];
}];

Or is there some sort of memory magic that AFNetworking does to prevent this?


Edit courtesy of Aaron Brager

Here you don't have a retain cycle. But if you did, in the completion block, you should convert weakSelf back into a strong reference so it won't get deallocated halfway through your completion block.

id strongSelf = weakSelf; 
[strongSelf.tableView reloadData];
1
Here you don't have a retain cycle. But if you did, in the completion block, you should convert weakSelf back into a strong reference so it won't get deallocated halfway through your completion block. (id strongSelf = weakSelf; [strongSelf.tableView reloadData];).Aaron Brager

1 Answers

6
votes

A retain cycle occurs when two or more objects have strong references to each other.

In this case, the block will have a strong reference to self, but self doesn't have a strong reference to the block, so you are fine here and no need to use weakSelf.

The case when you'll have a retain cycle and need to break it by using the weakSelf is when the class has a strong reference to the block too like in the following example:

typedef void (^CompletionCallback)(RequestObj* request, NSError* error);

@interface SomeClass() {
    /// Strong reference to the block
    CompletionCallback completionBlock;
}
@end

@implementation SomeClass()

- (void)someMethod {
    completionBlock = ^(RequestObj* request, NSError* error) {
        /// Strong reference to the class
        [self.tableView reloadData];
    };

    [AFnetworking requestGet:@"http://www.website.com" completionBlock:completionBlock];
}

@end

In this example, both completionBlock and self have strong references to each other, and therefore you'll have a retain cycle here and need to break it.