CATiledLayer 在 iPad 第 3 代放大时被移除和刷新

Posted

技术标签:

【中文标题】CATiledLayer 在 iPad 第 3 代放大时被移除和刷新【英文标题】:CATiledLayer being removed and refreshed while zoomed in iPad 3rd gen 【发布时间】:2012-05-13 01:04:10 【问题描述】:

当父 UIScrollView 放大时,我在 CATiledLayer 上遇到重绘问题。

我在 CATiledLayer 支持的 UIView 中呈现 PDF 页面。它后面有另一个 UIImageView,其中包含 CATiledLayer 将绘制的页面的低分辨率图像。当我放大时,它按预期工作。 CATiledLayer 将根据缩放级别渲染更高分辨率的图像。

缩放后出现问题。如果我放大然后只留下 iPad,显示的图像会模糊然后重新锐化。看起来 CATiledLayer 正在被移除,因为我在背景视图中看到模糊的低分辨率图像,然后 CATiledLayer 被重新绘制,即我看到了平铺效果和图像的重新锐化。如果我不理会应用程序并等待大约 30 到 40 秒,就会发生这种情况。我只在第三代 iPad(新 iPad、iPad3 等)上观察到它。我也在 iPad2s 上测试,还没有遇到这个问题。

还有其他人遇到过这个问题吗?任何已知的原因和可能的解决方案?

编辑:

我的 UIScrollViewDelegate 方法如下:

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

不确定这会有多大帮助,因为当问题发生时,滚动视图没有接收到输入。如上所述,pdf页面加载到CATiledLayer,然后我不理会iPad(设备没有接收到输入),CATiledLayer会自行重绘。

我还尝试在视图和平铺层上捕获对setNeedsDisplaysetNeedsDisplayInRect:setNeedsLayoutsetNeedsDisplayOnBoundsChange: 的调用,但是重绘发生时没有调用任何这些函数。当然,drawLayer:inContext: 会被调用,但跟踪仅显示在后台线程中启动了一些 Quartz 调用(正如预期的那样,因为平铺层在后台准备内容),所以它也无济于事。

提前致谢!

【问题讨论】:

会不会是因为 ipad 3 的高分辨率视网膜显示屏?您是否正确设置了 CATiledLayer contentsScale?同样在您的自定义 PDF 创建渲染代码中,您应该使用 UIGraphicsBeginImageContextWithOptions 并相应地设置比例 我没有使用 UIGraphicsBeginImageContextWithOptions,但我使用 CGContextScaleCTM 来设置比例。有区别吗?看起来我正在正确渲染pdf。我的问题是 CATiledLayer 会在一段时间后无缘无故地重绘自己。 您应该将 CATiledLayer contentsScale 设置为 [[UIScreen mainScreen] 比例] 能否请您发布一些 UIScrollViewDelegate 方法的代码,以便我们更好地处理您的流程? 我已经添加了委托方法。非常感谢任何见解。谢谢! 【参考方案1】:

您的应用的内存使用情况如何?如果出现内存警告,CATiledLayer 将丢弃其缓存并重绘。即使没有向应用程序发送内存警告(只是比通常的内存负载高),我也看到它这样做了。使用 Instruments 查看内存使用情况。您可能需要使用 OpenGL ES Driver 工具来查看图形内存的情况。

【讨论】:

我正在记录内存警告,但是当重绘发生时它不会触发。我会尝试用仪器检查。感谢您的信息! 那么你是怎么解决这个问题的呢?我们很多人都遇到同样的问题,解决方案会很棒【参考方案2】:

我与一位 Apple 工程师就此进行了交谈,简短的回答是 ios 只有 X 量的内存可用于缓存 CATiledLayer,并且在 iPad 的 Retina 显示屏上,像素太多,无法使用多个图层.

我一直在使用两个 CATileLayer 在顶部显示地图视图和绘图视图。我删除了第二个 CATiledLayer,问题就消失了。

【讨论】:

我明白了。很高兴知道。感谢分享! :)【参考方案3】:

我遇到了完全相同的问题。在我的情况下,它是由使用 UIGraphicsBeginImageContext() 函数引起的;这个函数没有考虑到比例,这会给视网膜显示器带来问题。解决方案是将调用替换为 UIGraphicsBeginImageContextWithOptions(),并将 scale(=third)参数设置为 0.0。

如果您的代码像我一样基于 Apple 的 Zooming PDF Viewer 示例代码,那么这也可能会解决您的问题。

【讨论】:

设置缩放到 0.0 是错误的...应该这样设置: UIGraphicsBeginImageContextWithOptions(frame.size, NO, [[UIScreen mainScreen] scale]); 你的方式当然也可以,但是将比例设置为 0.0 具有相同的效果。 developer.apple.com/library/ios/#documentation/uikit/reference/… 有趣。谢谢。不过,我没有调用 UIGraphicsBeginImageContext(),因为我正在使用drawlayer:inContext: 进行绘图。您是否使用其他方法? 我也使用它,但我使用 UIGraphicsBeginImageContext 来创建缩放时使用的模糊图像。 那么,UIGraphicsBeginImageContext 只是在模糊的背景图片中,而在drawLayer:inContext: 中没有UIGraphicsBeginImageContext 对吧?【参考方案4】:

Longshot,你有没有机会从非主线程调用视图上的任何方法?如果你这样做了,就会发生各种意想不到的怪事。

【讨论】:

是的,后台发生了一些事情,但它们都不应该调用视图。如果是这种情况,那么正如 Josh 所说,背景可能会占用内存并导致重绘。我明天回去工作看看。

以上是关于CATiledLayer 在 iPad 第 3 代放大时被移除和刷新的主要内容,如果未能解决你的问题,请参考以下文章

什么会导致 iPad(第 3 代)在启动时崩溃但在模拟器中工作?

iPad 视网膜模拟器中的 CATiledLayer 性能不佳

iOS CATiledLayer 崩溃

测试 iPad 第 4 代/Retina 显示屏

隐藏 CATiledLayer 平铺创建

可以在我自己的设备上发布应用程序(iPad 第 1 代 5.1.1)