Замедление просмотра CALayer со многими элементами

Привет, у меня проблема с производительностью CALayers в NSView на уровне слоя внутри NSScrollView. У меня есть представление прокрутки, которое я заполняю кучей экземпляров CALayer, расположенных один над другим. Прямо сейчас все, что я делаю, это ставлю границы вокруг них, чтобы я мог их видеть. В слое больше ничего нет.

Производительность кажется хорошей, пока у меня около 1500 или около того в представлении прокрутки. Когда я добавляю 1500, производительность получается великолепной, когда я прокручиваю список вниз, пока не доберусь до пункта 1000. Затем приложение внезапно начинает зависать. Это не постепенное замедление, которое я бы ожидал, если бы оно только достигло своей мощности. Это как приложение, попадающее в кирпичную стену.

Когда я вызываю CGContextFillRect в методе рисования слоев, замедление происходит вокруг элемента 300. Я предполагаю, что это как-то связано с заполнением памяти видеокарты или чем-то другим? Нужно ли что-то делать, чтобы освободить ресурсы CALayers, когда они не отображаются на экране в моем представлении прокрутки?

Я заметил, что если я не установлю NeedsDisplay на своих слоях, я смогу получить до 1500 элементов без замедлений. Однако это не решение, так как у меня есть несколько пользовательских чертежей, которые я должен выполнить на слое. Я не уверен, решит ли это проблему или просто заставит ее появиться с большим количеством элементов в слое. В идеале я хотел бы, чтобы это было полностью масштабируемым с тысячами элементов в представлении прокрутки (в пределах разумного, конечно). Реально, сколько из этих пустых элементов мне следует ожидать таким образом?

#import "ShelfView.h"
#import <Quartz/Quartz.h>

@implementation ShelfView

- (void) awakeFromNib
{
    CALayer *rootLayer = [CALayer layer];
    rootLayer.layoutManager = self;
    rootLayer.geometryFlipped = YES;

    [self setLayer:rootLayer];
    [self setWantsLayer:YES];

    int numItemsOnShelf = 1500;

    for(NSUInteger i = 0; i < numItemsOnShelf; i++) {
        CALayer* shelfItem = [CALayer layer];
        [shelfItem setBorderColor:CGColorCreateGenericRGB(1.0, 0.0, 0.0, 1.0)];
        [shelfItem setBorderWidth:1];
        [shelfItem setNeedsDisplay];
        [rootLayer addSublayer:shelfItem];
    }

    [rootLayer setNeedsLayout];
}

- (void)layoutSublayersOfLayer:(CALayer *)layer
{
    float y = 10;

    int totalItems = (int)[[layer sublayers] count];

    for(int i = 0; i < totalItems; i++)
    {
        CALayer* item = [[layer sublayers] objectAtIndex:i];

        CGRect frame = [item frame];            
        frame.origin.x = self.frame.size.width / 2 - 200;
        frame.origin.y = y;
        frame.size.width = 400;
        frame.size.height = 400;

        [CATransaction begin];
        [CATransaction setAnimationDuration:0.0];

        [item setFrame:CGRectIntegral(frame)];

        [CATransaction commit];
        y += 410;
    }

    NSRect thisFrame = [self frame];
    thisFrame.size.height = y;

    if(thisFrame.size.height < self.superview.frame.size.height) 
        thisFrame.size.height = self.superview.frame.size.height;

    [self setFrame:thisFrame];
}

- (BOOL) isFlipped
{
    return YES;
}

@end

1 ответ

Решение

Я узнал, что это потому, что я заполнял каждый слой пользовательским рисунком, казалось, что все они кэшируются как отдельные изображения, даже если они разделяют много общих данных, поэтому я переключился на создание дюжины CALayers, заполняя их "содержимое" свойство и добавление их в качестве подслоев в основной слой. Это, казалось, делало вещи НАМНОГО молниеноснее.

Другие вопросы по тегам