【问题标题】:CATiledLayer large image crashing appCATiledLayer 大图崩溃应用
【发布时间】:2010-06-27 03:40:41
【问题描述】:

这与另一篇文章有​​些相关——但那篇文章有点搞砸了——所以我从头开始:

我有一个 CATiledLayer,里面有一个巨大的图像 (5780x6700px)。

平铺层位于滚动视图中。当我开始滚动时,一切都很好,直到明显渲染了太多的瓷砖。然后我收到内存警告,应用程序崩溃。

当我收到内存警告时,我试图从视图中删除 tiledlayer,清除它的内容(rootLayer.contents = nil AND tiledLayer.contents = nil),然后将其重新附加到视图中。没用...

感谢您的任何意见...

编辑:

感谢到目前为止的提示。我的一些假设似乎是错误的。我将图像加载到一个函数中,然后保留它——我猜这与 CATiledLayer 的行为相矛盾。加上UIImage imageNamed: 似乎也引起了一些错误。 现在我将图像加载到drawLayer:(CALayer *) inContentext(CGContextRef) ctx 并使用UIImage imageWithContentsOfFile: 加载它。

这似乎可以正常工作而不会导致内存不足。

但是 - 瓷砖的绘制速度非常缓慢:(

这是我对 tiledLayer 的设置:

-(CATiledLayer *)initTiledLayers: (int)level{

    //[tiledLayer release];

    CGRect pageRect;

    CATiledLayer *myLayer = [CATiledLayer layer];
    myLayer.delegate = self;

    if(level == 1){     
        pageRect = CGRectMake(0,  0,  690, 800);
        myLayer.tileSize = CGSizeMake(800, 800);
        myLayer.levelsOfDetail = 10;
        myLayer.levelsOfDetailBias = 2;
    }else if(level == 2){
        pageRect = CGRectMake(0,  0,  1445, 1675);
        myLayer.tileSize = CGSizeMake(600, 600);
        myLayer.levelsOfDetail = 8;
        myLayer.levelsOfDetailBias = 2;
    }else if(level == 3){   
        pageRect = CGRectMake(0,  0,  2890, 3350);
        myLayer.tileSize = CGSizeMake(400, 400);
        myLayer.levelsOfDetail = 4;
        myLayer.levelsOfDetailBias = 1;
    }else if(level == 4){
        pageRect = CGRectMake(0,  0, 5780, 6700);
        myLayer.tileSize = CGSizeMake(150, 150);
        myLayer.levelsOfDetail = 4;
        myLayer.levelsOfDetailBias = 0;
    }

    myLayer.frame = pageRect;

    return myLayer;
    [myLayer release];
}

(int)level 指示要使用的图像(我在某些缩放级别上切换图像)。 Level4是最大的图像...

这里是drawLayer函数:

- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
{
    CGContextSetRGBFillColor(ctx, 1.0, 1.0, 1.0, 1.0);
CGContextFillRect(ctx, CGContextGetClipBoundingBox(ctx));
CGContextTranslateCTM(ctx, 0.0, layer.bounds.size.height);
CGContextClearRect(ctx, CGRectMake(0,0,layer.bounds.size.width, layer.bounds.size.height));
CGContextScaleCTM(ctx, 1.0, -1.0);

    UIImage *map = [UIImage imageWithContentsOfFile: [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"Karte0%d", actLevel] ofType:@"jpg"]];
    UIImage *wanderwege = [UIImage imageWithContentsOfFile: [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"Karte0%d_wanderwege", actLevel] ofType:@"png"]];
    UIImage *rhb = [UIImage imageWithContentsOfFile: [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"Karte0%d_rhb", actLevel] ofType:@"png"]];
    UIImage *abstecher = [UIImage imageWithContentsOfFile: [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"Karte0%d_abstecher", actLevel] ofType:@"png"]];

    CGRect imageRect = CGRectMake (0.0, 0.0, map.size.width, map.size.height);
    CGContextDrawImage (ctx, imageRect, [map CGImage]);

    imageRect = CGRectMake (0.0, 0.0, wanderwege.size.width, wanderwege.size.height);
    CGContextDrawImage (ctx, imageRect, [wanderwege CGImage]);

    imageRect = CGRectMake (0.0, 0.0, rhb.size.width, rhb.size.height);
    CGContextDrawImage (ctx, imageRect, [rhb CGImage]);

    imageRect = CGRectMake (0.0, 0.0, abstecher.size.width, abstecher.size.height);
    CGContextDrawImage (ctx, imageRect, [abstecher CGImage]);

}

是的 - 我知道 - 我实际上在上下文中绘制了 4 张图像。 PNG 是我需要动态添加到主图像的叠加层...

我尝试将图像合并为一个 - 但这似乎更消耗内存/cpu ;)

非常感谢任何进一步的帮助!

【问题讨论】:

  • 你能说得更具体一点吗?重置内容并重新附加时会发生什么?
  • 你是如何加载图像的? UIImage imageNamed 有一些内存泄漏问题(我怀疑缓存确实过度,但无论如何净效果是一样的)。
  • @Ben:当我重新附加图层时,它是黑色的(似乎是 emtpy)。但是在绘制了前几个图块之后,内存警告又回来了。我尝试了从非常小到非常大的每个瓷砖尺寸。我还将 LOD 设置为 2 到 100。偏差设置为 0 到 2。@Dad - 我确实使用 UIImage imageNamed 进行加载 - 会试一试(虽然,我不确定我之前是否尝试过:)

标签: iphone memory-leaks catiledlayer


【解决方案1】:

为什么要在委托回调中绘制所有图像?

问题是 CATiledLayer 将所有内容分解为矩形并将裁剪的上下文传递给委托回调: - (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx

所有矩形都会出现这种情况,因为它们数量众多,而且您绘制的图像又大又耗时,因此整个过程会持续“很长时间”。

在我的实践中,我有许多小对象,只有当它们在剪辑上下文定义的框架内可见时才会被渲染。

在您的情况下(1 个大 pdf),我会尝试仅绘制图像的一部分。不确定它是否有帮助:)

【讨论】:

    【解决方案2】:

    您需要拆分大图像,因为 iOS 必须在内存中保持图像未压缩。如果您将图像大小乘以每个像素 4 字节,那么这将消耗大量内存。

    您需要以某种方式预先将它们分成两半和四分之一并将它们缓存到磁盘,然后从那里显示图块。请参阅 WWDC 2010 滚动视图演讲,了解如何顺利完成。

    【讨论】:

      【解决方案3】:

      我发现,我没有正确使用 tiledLayer。此外,我使用 PNG 作为叠加层,并且必须正确设置 tiledLayer 上的混合模式以摆脱黑屏...

      [edit] 并且不要忘记(正如 Andrew 在下面提到的),必须将大图像切割成图块(例如,对于 PSD 进行缩放)。如果你在一张大图上使用平铺层,那就不行了……

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-08-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-09
        • 1970-01-01
        相关资源
        最近更新 更多