versiones guia español descargar actualizar ios objective-c performance calayer masking

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.