I've got a question regarding the following code:
@interface ViewController ()
@property (nonatomic, weak) CALayer *someLayer;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.someLayer = [CALayer layer];
self.someLayer.frame = CGRectMake(10.0, 10.0, 100.0, 100.0);
self.someLayer.backgroundColor = [UIColor yellowColor].CGColor;
[self.view.layer addSublayer:self.someLayer];
}
@end
From my understanding [CALayer layer]
should return an autoreleased value, which should live as long as the method call is in progress. It is then referenced by the weak property someLayer
.
Since the layer is later retained by the view's layer everything should be fine and the layer should appear.
What it does, but only on devices < iPhone 5S. At least when I run the code in the simulators.
On newer devices the layer won't be displayed. Changing the property attribute to strong solves the problem, but I'd like to know why the layer gets released immediately.
Do you have any hints how I can debug this behaviour to see what has changed?
Thanks!
Update:
Using self.someLayer = [CALayer [alloc]] init]
gives an appropriate warning
which I understand because when using alloc
the value is owned by the caller. Since the owner does not retain the value there's no strong reference.
An convenience initializer like layer
should autorelease an retained value, which should be accessible until the autorelease pool is drained. Also there's no warning by Xcode in this case.
Update #2: It gets more interesting... I tested the code on an iPhone 6 with iOS 8 and on an iPhone 4 with iOS 6. The layer won't be displayed on neither of them...
BUT
if I set a breakpoint at the line of the creation and step over it, the layer will be visible on simulators < iPhone 5S and on the devices.
How could I check what's going on under the hood?
Update #3 and some more explanation:
There is a great article on Big Nerd Ranch about this behaviour ARC Gotcha - Unexpectedly Short Lifetimes
A look at the disassembly for the code above shows how ARC inserts _objc_retainAutoreleasedReturnValue
From the article:
you can see ARC's "avoid the autorelease pool" optimization is being used: if a method returns an autoreleased object, and the caller doesn't otherwise need to hang on to it, ARC can avoid the trip to the autorelease pool. The method will return a retained object and objc_retainAutoreleasedReturnValue will dispose of it.
So, to avoid the problem, either declare a strong property (as I mentioned above) or have a look at @graver's answer.