Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CATiledLayer being removed and refreshed while zoomed in iPad 3rd gen

I'm experiencing a redraw problem on a CATiledLayer when the parent UIScrollView is zoomed in.

I'm rendering a PDF page in a CATiledLayer backed UIView. It has another UIImageView behind it, which contains a low-res image of the page that the CATiledLayer will draw. When I zoom in, it works as expected. The CATiledLayer will render a higher resolution image according to the zoom level.

The problem occurs after zooming. If I zoom in then just leave the iPad alone, the displayed image blurs then resharpens. It looks like the CATiledLayer is being removed, since I see the blurry low resolution image in the backing view, then the CATiledLayer gets redrawn, i.e. I see the tiling effect and the resharpening of the image. This happens if I just leave the app alone and wait about 30 to 40 seconds. I've only observed it on the iPad 3rd gen (New iPad, iPad3, whatever). I'm also testing on iPad2s and I have yet to encounter the issue.

Has anyone else encountered this problem? Any known cause and, possibly, solutions?

Edit:

My UIScrollViewDelegate methods are as follows:

// 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
}

Not sure how helpful this will be though, as the scrollview is not receiving input while the problem happens. As mentioned above, the pdf page is loaded to the CATiledLayer, then I leave the iPad alone (no input is received by the device), and the CATiledLayer will redraw by itself.

I've also tried catching calls to setNeedsDisplay, setNeedsDisplayInRect:, setNeedsLayout, and setNeedsDisplayOnBoundsChange: on both the view and the tiled layer, but the redraw happens without any of those functions getting called. drawLayer:inContext: gets called, of course, but the trace only shows some Quartz calls being started in a background thread (as expected, as tiled layers prepare the content in the background), so it is of no help either.

Thanks in advance!

like image 805
Altealice Avatar asked May 03 '12 13:05

Altealice


2 Answers

How is your app's memory usage looking? CATiledLayer will discard its cache and redraw if a memory warning occurs. I've seen it do this even without memory warnings being sent to the app (just a higher than usual memory load). Use Instruments to see memory usage. You may need to use the OpenGL ES Driver instrument to see what's going on with graphics memory.

like image 86
Josh Knauer Avatar answered Sep 27 '22 16:09

Josh Knauer


I spoke with an Apple engineer about this and the short answer is that iOS only has X amount of memory available for caching a CATiledLayer and on the Retina display of the iPad, there are just too many pixels to use more than one layer.

I had been using two CATileLayers to display a map view and a drawing view on top. I removed the second CATiledLayer and the problem went away.

like image 38
Brodie Avatar answered Sep 27 '22 16:09

Brodie