ios - guia - qgis manual
Problemas de rendimiento al utilizar muchas máscaras CALayer (2)
El cuarzo (drawRect :) es más lento que CoreAnimation por muchas razones: CALayer vs CGContext drawRect vs CALayer . Pero hay que usarlo correctamente.
En la documentación puedes ver algunos consejos. ImprovingCoreAnimationPerformance
Si desea un alto rendimiento, tal vez pueda intentar usar AsyncDisplayKit . Este marco permite crear aplicaciones fluidas y sensibles.
Estoy tratando de usar CAShapeLayer
para enmascarar un CALayer
en mi aplicación de iOS
ya que toma una fracción del CPU time
para enmascarar una imagen en lugar de enmascarar manualmente una en un bitmap context
;
Cuando tengo varias docenas o más de imágenes superpuestas, el CAShapeLayer
enmascarado UIImageView
se desplaza lentamente hacia mi toque.
Aquí hay un código de ejemplo:
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);
Con el código anterior, imageView
es muy lento. Sin embargo, reacciona instantáneamente si lo enmascaro manualmente en un 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);
Por cierto, aquí está el código para SLTUIImageView
, es solo una subclase de UIImageView
que responde a los toques (para cualquiera que se esté preguntando):
-(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];
}
¿Es posible optimizar de alguna manera la forma en que CAShapeLayer
está enmascarando el UIImageView
para UIImageView
el rendimiento? He tratado de averiguar dónde está usando el Time Profiler
en Instruments
cuello de botella, pero no puedo decir exactamente qué lo está causando.
He intentado configurar shouldRasterize
a YES
en ambas layer
y en layer.mask
pero ninguno parece tener ningún efecto. No estoy seguro de qué hacer.
Editar:
Hice más pruebas y descubrí que si uso solo un CALayer
normal para enmascarar otro CALayer (layer.mask = someOtherLayer)
tengo los mismos problemas de rendimiento. Parece que el problema no es específico de CAShapeLayer
sino que es específico de la propiedad de mask
de CALayer
.
Edición 2:
Entonces, después de aprender más sobre el uso de la Core Animation tool
en Instruments
, aprendí que la vista se muestra fuera de la pantalla cada vez que se mueve. La configuración debe shouldRaster
a YES
cuando comienza el toque y apagarlo cuando el toque termina hace que la vista permanezca verde (manteniendo así el caché) en los instruments
, pero el rendimiento sigue siendo terrible. Creo que esto se debe a que, aunque la vista se almacena en caché, si no es opaca, debe volver a representarse con cada fotograma.
Una cosa a destacar es que si solo hay unas pocas vistas enmascaradas (por ejemplo, alrededor de diez), el rendimiento es bastante bueno. Sin embargo, cuando aumentas eso a 100 or more
, el rendimiento se retrasa. Me imagino que esto se debe a que cuando uno se mueve sobre los demás, todos tienen que volver a representarse.
Mi conclusión es esta, tengo una de dos opciones.
Primero, debe haber alguna forma de enmascarar permanentemente una vista (renderizarla una vez y llamarla buena) Sé que esto se puede hacer a través del gráfico o la ruta de contexto de mapa de bits como muestro en mi código de ejemplo, pero cuando una capa enmascara su vista, sucede instantáneamente. Cuando lo hago en un contexto de mapa de bits como se muestra, es bastante lento (ya que en él casi no se puede comparar lo lento que es).
Segundo, debe haber faster
forma faster
rápida de hacerlo a través de la ruta de contexto de mapa de bits. Si hay un experto en enmascarar imágenes o vistas, su ayuda sería muy apreciada.
Usted ha avanzado bastante y creo que está casi en una solución. Lo que haría es simplemente una extensión de lo que ya has probado. Ya que dice que muchas de estas capas están "terminando" en las posiciones finales que permanecen constantes en relación con las otras capas, y la máscara. Así que simplemente convierta todas esas capas "terminadas" en un solo contexto de mapa de bits. De esa manera, cada vez que escriba una capa en ese contexto único, tendrá una capa menos de la que preocuparse, que está ralentizando el proceso de animación / renderizado.