我对以下代码有疑问:
@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]
会发出适当的警告
我理解,因为在使用alloc
时,该值由调用者拥有。由于所有者没有保留价值,因此没有强有力的参考。
像layer
这样的便利初始化程序应该自动释放一个保留值,该值应该可以访问,直到自动释放池耗尽。在这种情况下,Xcode也没有警告。
更新#2: 它变得更有趣...... 我在带有iOS 8的iPhone 6和带有iOS 6的iPhone 4上测试了代码。 这些图层都不会显示在它们中......
BUT
如果我在创建的行上设置断点并跨越它,则该层将在模拟器上显示< iPhone 5S和设备上的。
我怎样才能检查引擎盖下的情况?
更新#3以及更多解释:
关于这种行为,有一篇关于Big Nerd Ranch的文章ARC Gotcha - Unexpectedly Short Lifetimes
查看上面代码的反汇编显示ARC如何插入_objc_retainAutoreleasedReturnValue
来自文章:
你可以看到ARC"避免自动释放池"正在使用优化:如果方法返回一个自动释放的对象,并且调用者不需要依赖它,ARC可以避免访问自动释放池。该方法将返回一个保留的对象,objc_retainAutoreleasedReturnValue将处理它。
所以,为了避免这个问题,要么声明一个强大的属性(如上所述),要么看看@graver的答案。
答案 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 question和xcode debugger hide issue with weak proper,似乎调试器会对autorelease对象保持强烈的参考,因此它会被保留并显示出来。
您可以随时通过注销来测试self.somelayer
。
self.someLayer = [CALayer layer];
NSLog(@"someLayer is %@",_someLayer);
它应该记录为Null
,但在某些模拟器上它会有价值,这不应该发生。