CATiledLayer se elimina y se actualiza mientras se acerca el iPad de 3.ª generación

Estoy experimentando un problema de redibujado en un CATiledLayer cuando el UIScrollView principal está ampliado.

Estoy renderizando una página PDF en un UIView respaldado por CATiledLayer. Tiene otro UIImageView detrás, que contiene una imagen de baja resolución de la página que dibujará CATiledLayer. Cuando hago zoom, funciona como se esperaba. CATiledLayer generará una imagen de mayor resolución de acuerdo con el nivel de zoom.

El problema ocurre después de hacer zoom. Si amplío, dejo el iPad en paz, la imagen que se muestra se vuelve borrosa y luego se vuelve a enfocar. Parece que se está eliminando CATiledLayer, ya que veo la imagen borrosa de baja resolución en la vista de fondo, luego CATiledLayer se vuelve a dibujar, es decir, veo el efecto de mosaico y la nitidez de la imagen. Esto sucede si dejo la aplicación en paz y espero entre 30 y 40 segundos. Solo lo he observado en el iPad 3ra generación (Nuevo iPad, iPad3, lo que sea). También estoy probando en iPad2s y aún no he encontrado el problema.

¿Alquien más se ha encontrado con este problema? ¿Alguna causa conocida y, posiblemente, soluciones?

Edit:

Mis métodos UIScrollViewDelegate son los siguientes:

// currentPage, previousPage, and nextPage are the pdf page views
// that are having the refresh problem 

- (void)positionBufferedPages { 
  // performs math {code omitted}

  // then sets the center of the views
  [previousPage.view setCenter:...];        
  [nextPage.view setCenter:...];
}

- (void)hideBufferedPages {
  if ([previousPage.view isDescendantOfView:scrollView]) {
    [previousPage.view removeFromSuperview];
  }

  if ([nextPage.view isDescendantOfView:scrollView]) {
    [nextPage.view removeFromSuperview];
  }          
}

- (void)showBufferedPages {
  if (![previousPage.view isDescendantOfView:scrollView]) {
    [scrollView addSubview:previousPage.view];
  }

  if (![nextPage.view isDescendantOfView:scrollView]) {
    [scrollView addSubview:nextPage.view];
  }

  if (![currentPage.view isDescendantOfView:scrollView]) {
    [scrollView addSubview:currentPage.view];
  }
} 

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
  return currentPage.view;
}

- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view {
  [self hideBufferedPages];
}

- (void)scrollViewDidEndZooming:(UIScrollView *)scrollViewParam withView:(UIView *)view atScale:(float)scale {
  [self positionBufferedPages];
  [self showBufferedPages];    
}

- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
  // nothing relating to the pdf page view
  // but does set the center of some other subviews on top of the pdf page views
}

Sin embargo, no estoy seguro de cuán útil será esto, ya que la vista de desplazamiento no recibe información mientras ocurre el problema. Como se mencionó anteriormente, la página pdf se carga en CATiledLayer, luego dejo el iPad solo (el dispositivo no recibe ninguna entrada) y CATiledLayer se volverá a dibujar solo.

También he intentado capturar llamadas a setNeedsDisplay, setNeedsDisplayInRect:, setNeedsLayouty setNeedsDisplayOnBoundsChange: tanto en la vista como en la capa de mosaico, pero el redibujado ocurre sin que se llame a ninguna de esas funciones. drawLayer:inContext: se llama, por supuesto, pero el seguimiento solo muestra que algunas llamadas de Quartz se inician en un subproceso de fondo (como se esperaba, ya que las capas en mosaico preparan el contenido en segundo plano), por lo que tampoco es de ayuda.

Gracias de antemano!

preguntado el 03 de mayo de 12 a las 14:05

¿Podría ser por la pantalla retina de alta resolución del ipad 3? ¿Está configurando la escala de contenido de CATiledLayer correctamente? Además, en su código de representación de creación de PDF personalizado, debe usar UIGraphicsBeginImageContextWithOptions y establecer la escala en consecuencia:

No estoy usando UIGraphicsBeginImageContextWithOptions, pero uso CGContextScaleCTM para establecer la escala. ¿Hay una diferencia? Parece que estoy renderizando el pdf correctamente. Mi problema es que CATiledLayer de alguna manera se vuelve a dibujar sin motivo después de un tiempo. -

Debe establecer el contenido de CATiledLayerScale en la escala [[UIScreen mainScreen]] -

¿Puede publicar algún código de los métodos UIScrollViewDelegate, para que podamos manejar mejor su proceso? -

He agregado los métodos de delegado. Cualquier idea es muy apreciada. ¡Gracias! -

4 Respuestas

¿Cómo se ve el uso de memoria de su aplicación? CATiledLayer descartará su caché y volverá a dibujar si se produce una advertencia de memoria. Lo he visto hacer esto incluso sin que se envíen advertencias de memoria a la aplicación (solo una carga de memoria superior a la habitual). Use Instrumentos para ver el uso de la memoria. Es posible que deba usar el instrumento OpenGL ES Driver para ver qué sucede con la memoria gráfica.

contestado el 11 de mayo de 12 a las 12:05

Estoy registrando advertencias de memoria, pero no se activa cuando ocurre el redibujado. Intentaré comprobar con instrumentos. Gracias por la info! - Altealice

Entonces, ¿cómo resolviste este problema? Muchos de nosotros tenemos el mismo problema y una solución sería genial: Brodie

Hablé con un ingeniero de Apple sobre esto y la respuesta corta es que iOS solo tiene X cantidad de memoria disponible para almacenar en caché un CATiledLayer y en la pantalla Retina del iPad, hay demasiados píxeles para usar más de una capa.

Había estado usando dos CATileLayers para mostrar una vista de mapa y una vista de dibujo en la parte superior. Eliminé el segundo CATiledLayer y el problema desapareció.

Respondido el 01 de junio de 12 a las 02:06

Veo. Bueno saber. ¡Gracias por compartir! :) - Altealice

He tenido exactamente el mismo problema. En mi caso, fue causado por el uso de la función UIGraphicsBeginImageContext(); esta función no tiene en cuenta la escala, lo que da problemas en una pantalla retina. La solución fue reemplazar la llamada con UIGraphicsBeginImageContextWithOptions(), con el parámetro de escala (=tercero) establecido en 0.0.

Si basó su código en el código de muestra Zooming PDF Viewer de Apple, como hice yo, es probable que esto también resuelva su problema.

contestado el 03 de mayo de 12 a las 15:05

la configuración para escalar a 0.0 es falsa... debe establecerse así: UIGraphicsBeginImageContextWithOptions(frame.size, NO, [[UIScreen mainScreen] scale]); - lefteris

Tu manera también funciona, por supuesto, pero establecer la escala en 0.0 tiene el mismo efecto. desarrollador.apple.com/library/ios/#documentation/uikit/reference/… - usuario1340450

Interesante. Gracias. Sin embargo, no estoy llamando a UIGraphicsBeginImageContext(), ya que estoy dibujando usando drawlayer:inContext:. ¿Está utilizando un método diferente? - Altealice

También lo uso, pero usé UIGraphicsBeginImageContext para crear la imagen borrosa que se usa al hacer zoom. - usuario1340450

Entonces, UIGraphicsBeginImageContext solo está en la imagen de respaldo borrosa, pero no hay UIGraphicsBeginImageContext en drawLayer:inContext:, ¿verdad? - Altealice

Longshot, ¿hay alguna posibilidad de que esté llamando a algún método en las vistas del hilo no principal? Si lo haces, pueden suceder todo tipo de cosas funky inesperadas.

contestado el 11 de mayo de 12 a las 23:05

Sí, hay cosas sucediendo en segundo plano, pero ninguna de ellas debería llamar a la vista. Si este es el caso, entonces el material de fondo podría estar consumiendo memoria y provocando redibujados como dice Josh. Lo comprobaré mañana cuando vuelva al trabajo. - Altealice

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.