CALayer图层未自动释放

时间:2014-11-21 13:05:52

标签: ios objective-c core-animation automatic-ref-counting

我对以下代码有疑问:

@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

从我的理解[CALayer layer]应该返回一个自动释放的值,只要方法调用正在进行中,该值就应该存在。然后由弱属性someLayer引用它。 由于图层稍后由视图层保留,因此一切都应该很好并且应该出现图层。 它做了什么,但仅限于设备< iPhone 5S。至少当我在模拟器中运行代码时。

在较新的设备上,该图层将无法显示。 将property属性更改为strong可以解决问题,但我想知道为什么该层会立即释放。

您是否有任何提示我如何调试此行为以查看更改内容?

谢谢!

更新

使用self.someLayer = [CALayer [alloc]] init]会发出适当的警告 Xcode warning

我理解,因为在使用alloc时,该值由调用者拥有。由于所有者没有保留价值,因此没有强有力的参考。 像layer这样的便利初始化程序应该自动释放一个保留值,该值应该可以访问,直到自动释放池耗尽。在这种情况下,Xcode也没有警告。

更新#2: 它变得更有趣...... 我在带有iOS 8的iPhone 6和带有iOS 6的iPhone 4上测试了代码。 这些图层都不会显示在它们中......

BUT

如果我在创建的行上设置断点并跨越它,则该层将在模拟器上显示< iPhone 5S和设备上的。

enter image description here

我怎样才能检查引擎盖下的情况?

更新#3以及更多解释

关于这种行为,有一篇关于Big Nerd Ranch的文章ARC Gotcha - Unexpectedly Short Lifetimes

查看上面代码的反汇编显示ARC如何插入_objc_retainAutoreleasedReturnValue

来自文章:

  

你可以看到ARC"避免自动释放池"正在使用优化:如果方法返回一个自动释放的对象,并且调用者不需要依赖它,ARC可以避免访问自动释放池。该方法将返回一个保留的对象,objc_retainAutoreleasedReturnValue将处理它。

所以,为了避免这个问题,要么声明一个强大的属性(如上所述),要么看看@graver的答案。

2 个答案:

答案 0 :(得分:2)

由于您的someLayer属性较弱,因此无法对您的图层进行强有力的引用。您应该像这样更改代码:

...
CALayer *layer = [CALayer layer]; // by default layer this is __strong, so layer holds a strong reference until the end of the scope
[self.view.layer addSublayer:layer]; // Now self.view.layer retains the layer
self.somelayer = layer; // weak reference it

self.someLayer.frame = CGRectMake(10.0, 10.0, 100.0, 100.0);
self.someLayer.backgroundColor = [UIColor yellowColor].CGColor;

// In the end of the scope layer would be released, but it's also retained by self.view.layer and weak referenced by self.someLayer
...

答案 1 :(得分:1)

@graver的代码在真正的iPhone 6设备上为我工作,这意味着显示了图层,你应该总是依靠真实设备而不是模拟器。您可以参考this questionxcode debugger hide issue with weak proper,似乎调试器会对autorelease对象保持强烈的参考,因此它会被保留并显示出来。

您可以随时通过注销来测试self.somelayer

self.someLayer = [CALayer layer];
NSLog(@"someLayer is %@",_someLayer);

它应该记录为Null,但在某些模拟器上它会有价值,这不应该发生。