CATiledLayer大图像崩溃的应用程序

时间:2010-06-27 03:40:42

标签: iphone memory-leaks catiledlayer

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

我有一个带有巨大图像的CATiledLayer(5780x6700px)。

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

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

感谢任何输入......

修改

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

这似乎可以在不导致内存不足的情况下发挥作用。

然而 - 瓷砖画得很慢:(

这是我对tilesLayer的设置:

-(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是叠加层,我需要动态添加到主图像...

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

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

3 个答案:

答案 0 :(得分:2)

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

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

对于所有矩形都会发生这种情况,因为它们中有很多,并且您绘制的图像很大且耗时,整个过程会持续“年龄”。

在我的练习中,我有许多小物件,只有在被修剪的上下文定义的帧内可见时才会被渲染。

在你的情况下(1大pdf)我会尝试只绘制图像的一部分。不知道它是否有帮助:))

答案 1 :(得分:1)

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

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

答案 2 :(得分:0)

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

[编辑]并且不要忘记(正如安德鲁在下面提到的那样),必须将大图像切割成图块(例如,缩放PSD)。如果您使用带有一个大图像的平铺图层,则它不起作用...