使用许多CALayer掩码时的性能问题

时间:2013-06-11 21:44:51

标签: ios objective-c performance calayer masking

我正在尝试使用CAShapeLayer屏蔽我的CALayer应用中的iOS,因为它需要CPU time的一小部分来屏蔽图像而不是手动屏蔽图像一个bitmap context;

当我有几十个或更多图像叠加在一起时,CAShapeLayer蒙版UIImageView移动到我的触摸速度很慢。

以下是一些示例代码:

UIImage *image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle]pathForResource:@"SomeImage.jpg" ofType:nil]];
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddEllipseInRect(path, NULL, CGRectMake(0.f, 0.f, image.size.width * .25, image.size.height * .25));

for (int i = 0; i < 200; i++) {

    SLTUIImageView *imageView = [[SLTUIImageView alloc]initWithImage:image];
    imageView.frame = CGRectMake(arc4random_uniform(CGRectGetWidth(self.view.bounds)), arc4random_uniform(CGRectGetHeight(self.view.bounds)), image.size.width * .25, image.size.height * .25);

    CAShapeLayer *shape = [CAShapeLayer layer];
    shape.path = path;
    imageView.layer.mask = shape;

    [self.view addSubview:imageView];
    [imageView release];

}
CGPathRelease(path);

使用上面的代码,imageView非常滞后。但是,如果我在bitmap context

中手动屏蔽它,它会立即作出反应
UIImage *image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle]pathForResource:@"3.0-Pad-Classic0.jpg" ofType:nil]];
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddEllipseInRect(path, NULL, CGRectMake(0.f, 0.f, image.size.width * .25, image.size.height * .25));


for (int i = 0; i < 200; i++) {

    UIGraphicsBeginImageContextWithOptions(CGSizeMake(image.size.width * .25, image.size.height * .25), NO, [[UIScreen mainScreen]scale]);
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    CGContextAddPath(ctx, path);
    CGContextClip(ctx);

    [image drawInRect:CGRectMake(-(image.size.width * .25), -(image.size.height * .25), image.size.width, image.size.height)];
    UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    SLTUIImageView *imageView = [[SLTUIImageView alloc]initWithImage:finalImage];
    imageView.frame = CGRectMake(arc4random_uniform(CGRectGetWidth(self.view.bounds)), arc4random_uniform(CGRectGetHeight(self.view.bounds)), finalImage.size.width, finalImage.size.height);

    [self.view addSubview:imageView];
    [imageView release];

}
CGPathRelease(path);

顺便说一下,这是SLTUIImageView的代码,它只是UIImageView的一个简单子类,可以响应触摸(对于任何想知道的人):

-(id)initWithImage:(UIImage *)image{

    self = [super initWithImage:image];
    if (self) {
        self.userInteractionEnabled = YES;
    }
    return self;
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    [self.superview bringSubviewToFront:self];
}

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{

    UITouch *touch = [touches anyObject];
    self.center = [touch locationInView:self.superview];
}

是否有可能以某种方式优化CAShapeLayer屏蔽UIImageView的方式,从而提高性能?我试图找出瓶颈在Time Profiler中使用Instruments的位置,但我无法确切地知道是什么导致了它。

我已尝试在shouldRasterizeYES上将layer设置为layer.mask,但似乎都没有任何效果。我不知道该怎么做。

修改

我做了更多测试,发现如果我只使用常规CALayer来掩盖另一个CALayer (layer.mask = someOtherLayer),我会遇到相同的性能问题。问题似乎不是CAShapeLayer特有的 - 而是特定于mask的{​​{1}}属性。

编辑2:

因此,在了解了CALayer中使用Core Animation tool的更多信息之后,我了解到视图每次移动时都会在屏幕外呈现。触摸开始时将Instruments设置为shouldRaster,触摸结束时将其设置为关闭会使视图保持绿色(从而保持缓存)YES,但性能仍然很糟糕。我相信这是因为即使视图被缓存,如果它不是不透明的,那么它仍然必须用每个帧重新渲染。

强调的一点是,如果只有少数视图被屏蔽(甚至大约十个),那么性能非常好。但是,当您将其增加到instruments时,性能会滞后。我想这是因为当一个人移过其他人时,他们都必须重新渲染。

我的结论是这样,我有两种选择之一。

首先,必须有一些方法永久地屏蔽视图(渲染一次并称之为好)。我知道这可以通过我在示例代码中显示的图形或位图上下文路由来完成,但是当图层屏蔽其视图时,它会立即发生。当我在如图所示的位图上下文中执行它时,它非常慢(因为它几乎甚至无法比较它的速度有多慢)。

其次,必须有一些100 or more方法通过位图上下文路由来实现。如果有专家屏蔽图像或视图,他们的帮助将非常感激。

2 个答案:

答案 0 :(得分:1)

你已经走得很远,我相信几乎是一个解决方案。我要做的只是你已经尝试过的扩展。因为你说很多这些层在最终位置“结束”,相对于其他层和掩码保持不变。所以简单地将所有那些“完成”的层渲染到单个位图上下文。这样,每次你在一个单独的上下文中写出一个图层时,你就会有一个较少的图层来担心这会减慢动画/渲染过程的速度。

答案 1 :(得分:0)

Quartz(drawRect :)比CoreAnimation慢,原因有很多:CALayer vs CGContext drawRect vs CALayer。但是有必要正确使用它。

在文档中,您可以看到一些建议。 ImprovingCoreAnimationPerformance

如果您想要高性能,也许可以尝试使用AsyncDisplayKit。该框架允许创建流畅且响应迅速的应用程序。