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

@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次。
但是,如果将其设置为1,则在此之前不会调用TestLayer中的dealloc,它会返回应用程序didFinishLaunchingWithOptions:。
实际上只是调用[test setNeedsLayout];没有添加任何子层会导致TestLayer泄漏。

我正在使用类似的代码来生成一些脱机内容,并且不会用于仅使用预生成的脱机内容的最终应用程序。

有谁知道我的TestLayer引用了什么,我如何说服它释放它?

最佳答案

让我猜测-您在项目中不使用ARC吗?

我尝试了几种方法来重现您对上述泄漏的主张,但找不到任何办法可以实现它。

我为您的班级添加了标签:

@interface TestLayer: CALayer
@property (nonatomic, assign) int tag;
@end

@implementation TestLayer
-(void)dealloc
{
    NSLog(@"dealloc called for %d", self.tag);
}
@end


首先,我在完全相同的地方尝试了您的代码AppDelegate:

for (int i=0; i<10; i++) {
    @autoreleasepool {
        TestLayer* test = [TestLayer layer];
        test.tag = 100;
        CALayer* l = [CALayer layer];
        [test addSublayer:l];
        [l removeFromSuperlayer];
        l = nil;
        test = nil;
    }
}


每次打印dealloc

然后,在我的第一个视图控制器中,我对其进行了少许修改:

- (void)viewDidLoad {
    [super viewDidLoad];

    tl = [TestLayer layer]; // its an ivar
    tl.tag = 100;
    for (int i=0; i<10; i++) {
      @autoreleasepool {
        TestLayer *l = [TestLayer layer];
        l.tag = i + 10;
        [tl addSublayer:l];
        [tl removeFromSuperlayer];  // tried this, also tried commenting it out
      }
    }
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
        NSArray *sl = [self->tl.sublayers copy];
        for (TestLayer *l in sl) {
            [l removeFromSuperlayer];
        }
        self->tl = nil;
    });

}


我唯一可以得出的结论是您没有使用ARC,您应该已经提到过。

PS:如果不使用ARC,我只能假定CALayer layer返回的保留计数为1的对象,并且不会自动释放。如果是这样,则需要显式发送一条release消息。

07-27 13:40