CALayer 层未自动发布

Posted

技术标签:

【中文标题】CALayer 层未自动发布【英文标题】:CALayer layer not autoreleased 【发布时间】:2014-11-21 13:05:51 【问题描述】:

我有一个关于以下代码的问题:

@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 引用。 由于该层后来被视图层保留,所以一切都应该没问题,并且该层应该出现。 它的作用,但仅适用于

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

您是否有任何提示我可以调试此行为以查看发生了什么变化?

谢谢!

更新:

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

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

更新 #2: 变得更有趣了…… 我在装有 ios 8 的 iPhone 6 和装有 iOS 6 的 iPhone 4 上测试了代码。 图层不会显示在它们上面...

但是

如果我在创建的行设置断点并越过它,该层将在模拟器

我怎样才能检查引擎盖下发生了什么?

更新 #3 和更多解释

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

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

来自文章:

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

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

【问题讨论】:

ARC 已开启?很奇怪,也许你应该在设备上调试。我不相信模拟器。 【参考方案1】:

由于您的 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
...

【讨论】:

为什么原始代码适用于设备 这是个好问题。理论上不应该。您是在设备上测试过还是只在模拟器上测试过? @graver 请查看我的更新。我在 iPhone 6 上测试过,结果和模拟器上的一样,也就是说图层是不可见的。 我能够在装有 iOS 6 的 iPhone 4 上对其进行测试,并添加了更多信息。【参考方案2】:

@graver 的代码在真正的 iPhone 6 设备上适用于我,这意味着显示层,您应该始终依赖真实设备而不是模拟器。可以参考this question和xcode debugger hide issue with weak proper,看来调试器对autorelease对象有很强的引用,所以保留并显示。

您始终可以通过注销来测试self.somelayer

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

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

【讨论】:

感谢您的意见!我用一些进一步的发现更新了我的问题。 你测试了吗,在哪里添加[uicolor self]

以上是关于CALayer 层未自动发布的主要内容,如果未能解决你的问题,请参考以下文章

使用自动布局时,如何调整 CALayer 的锚点?

动画 CALayer

CALayer autoresizingMask 不适用于 iOS SDK?

相机预览层未显示

UIView 图层未正确屏蔽

Vue JS视图层未更新