CALayer 使用 ARC 导致内存泄漏

CALayer causing memory leak with ARC

我花了一段时间来理解我的代码中的一些大内存泄漏,所以在简化代码之后剩下的是:

@interface TestLayer: CALayer
@end
@implementation TestLayer
-(void)dealloc
{
    NSLog(@"dealloc called");
}
@end

@implementation AppDelegate
#define ENABLE_LEAK 1
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    for (int i=0; i<10; i++) {
        @autoreleasepool {
            TestLayer* test = [TestLayer layer];
#if ENABLE_LEAK
            CALayer* l = [CALayer layer];
            [test addSublayer:l];
            [l removeFromSuperlayer];
            l = nil;
#endif
            test = nil;
        }
    }
return YES;
}
.....

如果ENABLE_LEAK设置为0,TestLayer中的dealloc被正确调用10次。 但是,如果它在 TestLayer 中设置为 1 dealloc,则在此之前不会调用应用程序:didFinishLaunchingWithOptions: returns。 实际上只是调用 [test setNeedsLayout];不添加任何子层会导致 TestLayer 泄漏。

我正在使用类似的代码来生成一些离线内容,不会用于最终应用程序,它只会使用预生成的离线内容。

有人知道什么在引用我的 TestLayer 吗?我怎样才能说服它发布它?

正如 Cristi 在其中一条评论中建议的那样,我所有关于 内存泄漏 CALayer 的问题都通过使用 CATransaction.flush()

它就像一个魅力

doc for CATransaction 中可以看出,如果您修改图层而不显式打开图层,则会创建一个隐式事务。此事务会在下一次 运行 循环迭代时自动刷新。由于您在单个主线程方法调用中进行迭代,因此 运行 循环不会关闭。正如您所说,deallocs 确实会在您 return 之后被调用。据推测,事务将所有操作(包括添加和删除)存储到某种保留它们的堆栈中,并且它仅在事务结束时才得到处理。因此,您看到的行为是预期的,如果您确实需要在单个 运行 循环迭代中清理引用,您可能希望自己显式处理事务而不是刷新隐式事务,这可能会导致性能不佳或意外副作用。