CALayer вызывает утечку памяти с ARC - PullRequest
0 голосов
/ 04 сентября 2018

Я некоторое время пытаюсь понять какую-то большую утечку памяти в моем коде, поэтому после упрощения кода осталось следующее:

@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 вызывается правильно 10 раз. Однако, если для этого параметра установлено значение 1, dealloc в TestLayer не вызывается до этого, приложение: didFinishLaunchingWithOptions: возвращает. На самом деле просто вызов [test setNeedsLayout]; без добавления каких-либо подслоев вызывает утечку TestLayer.

Я использую аналогичный код для создания некоторого автономного контента и не буду использоваться для конечного приложения, которое будет просто использовать предварительно сгенерированный автономный контент.

Кто-нибудь знает, что ссылается на мой TestLayer и как я могу убедить его выпустить его?

1 Ответ

0 голосов
/ 04 сентября 2018

Дайте угадаю - вы не используете 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.

...