0
votes

Per the transitioning to ARC release notes, when referencing self within a block one should use weak references in order to avoid a strong reference/retain cycle:

MyViewController *myController = [[MyViewController alloc] init…];
// ...
MyViewController * __weak weakMyController = myController;
myController.completionHandler =  ^(NSInteger result) {
MyViewController *strongMyController = weakMyController;
if (strongMyController) {
    // ...
    [strongMyController dismissViewControllerAnimated:YES completion:nil];
    // ...
}
else {
    // Probably nothing...
}
};

Sometimes, I will get a compiler warning that referencing self in the block is likely to lead to a retain cycle. Does the absence of the warning imply that a retain cycle will not be created? Why is the warning qualified as "likely" to lead to a retain cycle?

1
I think the use of the word "likely" is because the compiler cannot know for certain if a cycle will be created. It only uses the reference to self within the block as a heuristic to suggest that a cycle could likely be created.Anurag

1 Answers

3
votes

Does the absence of the warning imply that a retain cycle will not be created?

No. The compiler is able to determine certain conditions from which you may create a retain cycle but it is impossible for it to rule out the possibility that you may create one. As an example consider the following class:

@interface MyClass : NSObject

@property (readwrite, strong) id myObject;

@end

and the code fragment in a different class:

MyClass *one = [MyClass new];
MyClass *two = [MyClass new];

one.myObject = two;
two.myObject = one; // created a strong cycle...

For a compiler to even spot this simple cycle requires flow analysis across multiple classes, and in general this problem is unsolvable by the compiler (you can scan for/spot the creation of cycles at runtime, ARC does not do this).

Why is the warning qualified as "likely" to lead to a retain cycle?

Creating a cycle itself is not wrong or bad. A cycle is only an issue if it becomes orphaned; i.e. no live references refer to it and it is only the cyclic references which cause the objects in the cycle to remain alive.

When the compiler sees a strong reference to self within a block being created it knows a live strong cycle will be created, but it cannot determine (i.e. unsolvable in general as above) whether that cycle will be later broken before the block is no longer required or whether the creating object and the block will form an orphaned cycle. Hence the use of a non-definitive "likely".