CALayer 滚动视图因许多项目而变慢

发布于 2024-11-02 08:16:13 字数 2201 浏览 0 评论 0原文

嘿,我在 NSScrollView 内的层支持的 NSView 中遇到了 CALayers 的性能问题。我有一个滚动视图,其中填充了一堆 CALayer 实例,一个堆叠在下一个实例之上。现在我所做的就是在它们周围设置边框,这样我就可以看到它们。该层中没有其他任何内容。

性能看起来还不错,直到我的滚动视图达到 1500 左右。当我输入 1500 时,当我向下滚动列表时,性能非常好,直到到达第 1000 项左右。然后应用程序突然开始挂起。这并不是一个逐渐放缓的过程,而这正是我所期望的,如果它刚刚达到其容量的话。就像应用程序撞到了砖墙一样。

当我在图层的绘制方法中调用 CGContextFillRect 时,速度减慢发生在第 300 项附近。我假设这可能与显卡内存填满或其他原因有关?当 CALayers 在滚动视图中位于屏幕外时,我是否需要执行某些操作来释放 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

Hey, I'm having a performance problem with CALayers in a layer backed NSView inside an NSScrollView. I've got a scroll view that I populate with a bunch of CALayer instances, stacked one on top of the next. Right now all I am doing is putting a border around them so I can see them. There is nothing else in the layer.

Performance seems fine until I have around 1500 or so in the scroll view. When I put 1500 in, the performance is great as I scroll down the list, until I get to around item 1000. Then very suddenly the app starts to hang. It's not a gradual slowdown which is what I would expect if it was just reaching it's capacity. It's like the app hits a brick wall.

When I call CGContextFillRect in the draw method of the layers, the slowdown happens around item 300. I'm assuming this has something to do with maybe the video card memory filling up or something? Do I need to do something to free the resources of the CALayers when they are offscreen in my scroll view?

I've noticed that if I don't setNeedsDisplay on my layers, I can get to the end of 1500 items without slowdowns. This is not a solution however, as I have some custom drawing that I must perform in the layer. I'm not sure if that solves the problem, or just makes it show up with a greater number of items in the layer. Ideally I would like this to be fully scalable with thousands of items in the scroll view (within reason of course). Realistically, how many of these empty items should I expect to be able to display in this way?

#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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

挽心 2024-11-09 08:16:13

我发现这是因为我用自定义绘图填充每个图层,它们似乎都被缓存为单独的图像,即使它们共享很多通用数据,所以我转而只创建十几个 CALayers,填充它们的“内容”属性,并将它们作为子图层添加到主图层中。这似乎让事情变得更加快捷。

I found out it was because I was filling each layer with custom drawing, they seemed to all be cached as separate images, even though they shared a lot of common data, so I switched to just creating a dozen CALayers, filling their "contents" property, and adding them as sublayers to a main layer. This seemed to make things MUCH zippier.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文