【问题标题】:Memory issues with Core GraphicsCore Graphics 的内存问题
【发布时间】:2014-01-10 13:48:09
【问题描述】:

我使用 Core Graphics 的原语“手动”绘制了一张表格。 当我单击一个按钮时,视图会重新绘制。 问题是,当我在 Instruments 中分析代码时,VM 区域不断增加,而 Heap 和 Anonymous VM 会波动(我会预料到的)。

还有关于CoreAnimation的细节:

我的 drawRect 的摘录:

- (void)drawRect:(CGRect)rect
{

    // Drawing code
    CGContextRef context     = UIGraphicsGetCurrentContext();

    CGRect paperRect         = CGRectMake(self.bounds.origin.x+hourLabelSize+self.marginX,
                                           10 +self.cellBorder  ,
                                          self.bounds.size.width,
                                          self.cellHeight * 48
                                          );
    // custom shadow
    drawLinearGradient(context, paperRect, whiteColor.CGColor, lightGrayColor.CGColor);
    CGContextSaveGState(context);
    CGFloat outerMargin = 5.0f;
    CGFloat eventSize;
    // Draw table
    CGRect hourRect;
    CGRect outerRect;
    CGMutablePathRef outerPath;
    CGRect strokeRect;
    CGRect rowRect;
    for (int j=0; j < 7;j++)
    {
    for (int i=0; i < numberOfRows; i++)
    {
        // Odd index means we are in the half of an hour


        if ( (i%2) == 0)
        {
            [hour setString:[NSString stringWithFormat:@"%d:00",(int)floor(i/2)]];
            // Draw box around hours //
            if (j == 0 && i >0)
            {
                CGContextSaveGState(context);

                hourRect   = CGRectMake(5, i*cellHeight-5, hourLabelSize, 28);
                outerRect  = CGRectInset(hourRect, outerMargin, outerMargin);
                outerPath = newRoundedRectForRect(outerRect, 6.0);
                CGContextAddPath(context, outerPath);
                CFRelease(outerPath); // <--- This solve the leak!!

                // Draw gradient
                strokeRect = CGRectInset(hourRect, 5.0, 5.0);
                CGContextSetStrokeColorWithColor(context, boxColor.CGColor);
                CGContextSetLineWidth(context, 1.0);
                CGContextStrokeRect(context, strokeRect);
                drawLinearGradient(context, strokeRect, whiteColor.CGColor, lightGrayColor.CGColor);
                CGContextRestoreGState(context);

            }
        }
        else
        {
            [hour setString:[NSString stringWithFormat:@"%d:30",(int)floor(i/2)]];

        }

        // Draw hours
        if (j == 0 && i > 0)
            [hour drawInRect:CGRectMake(0, i*cellHeight, hourLabelSize+10, 26) withFont:font lineBreakMode:NSLineBreakByClipping alignment:NSTextAlignmentCenter];
        // Draw row
        CGContextBeginPath(context);
        CGContextSetStrokeColorWithColor(context, boxColor.CGColor);
        CGContextSetLineWidth(context, self.cellBorder);
        rowRect   = CGRectMake(j*cellWidth + hourLabelSize +self. marginX - self.cellBorder/2, i*cellHeight+10 + self.cellBorder / 2, cellWidth , cellHeight);
        CGContextStrokeRect(context, rowRect);


} //


    CGContextFlush(context);
    CGContextRestoreGState(context);

我不明白的第一件事是为什么我会看到 VM:CoreAnimation。 CoreGraphics 是核心动画的一部分吗? 其次,我应该将其视为分配不当的症状:VM 区域、XCode 测量或 Head 和 Anonymous? 问候!

[编辑]

createRoundedRect如下

CGMutablePathRef newRoundedRectForRect(CGRect rect, CGFloat radius)
{
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathMoveToPoint(path, NULL, CGRectGetMidX(rect), CGRectGetMinY(rect));
    CGPathAddArcToPoint(path, NULL, CGRectGetMaxX(rect), CGRectGetMinY(rect), CGRectGetMaxX(rect), CGRectGetMaxY(rect), radius);
    CGPathAddArcToPoint(path, NULL, CGRectGetMaxX(rect), CGRectGetMaxY(rect), CGRectGetMinX(rect), CGRectGetMaxY(rect), radius);
    CGPathAddArcToPoint(path, NULL, CGRectGetMinX(rect), CGRectGetMaxY(rect), CGRectGetMinX(rect), CGRectGetMinY(rect), radius);
    CGPathAddArcToPoint(path, NULL, CGRectGetMinX(rect), CGRectGetMinY(rect), CGRectGetMaxX(rect), CGRectGetMinY(rect), radius);
    CGPathCloseSubpath(path);


    return path;
}:

还有drawLineGradient.m

void drawLinearGradient(CGContextRef context, CGRect rect, CGColorRef startColor, CGColorRef endColor)
{
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGFloat locations[] = { 0.0, 1.0 };

    NSArray *colors = @[(__bridge id) startColor, (__bridge id) endColor];

    CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef) colors, locations);

CGPoint startPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect));
CGPoint endPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect));

CGContextSaveGState(context);
CGContextAddRect(context, rect);
CGContextClip(context);
CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
CGContextRestoreGState(context);

CGGradientRelease(gradient);
CGColorSpaceRelease(colorSpace);
colors = nil;

}

【问题讨论】:

  • 静态分析器告诉你什么?我怀疑 drawLinearGradient 方法,因为它没有在这里显示,还有你的 createRoundedRect...
  • 查看我编辑的答案,我添加了一些代码。

标签: ios memory-management memory-leaks core-graphics core-animation


【解决方案1】:

您看到核心动画的原因是因为所有 iOS 视图都是基于层的视图。 您泄漏的原因是您释放了路径。 ARC 不管理 Core Foundation 对象。

【讨论】:

  • 然后呢?你会说“我没有释放路径”吗?我编辑了问题并插入了完整的代码。我在最后释放路径。
  • 同样在 newRoundedRectForRect() 中释放内存管理规则仍然适用。
  • 如果必须返回路径如何释放?
  • @giuseppe:您不必也不应该在newRoundedRectForRect 中发布它,尽管您应该将其重命名为createRoundedRectPathForRect 以澄清(a)它返回所有权,这调用者 (drawRect:) 必须释放,并且 (b) 它创建一个路径,而不是一个矩形。
  • @giuseppe:替代方案是roundedRectPathForRect 返回CFAutorelease(path)drawRect: 不释放它。这仅适用于 iOS 7 或更高版本。
猜你喜欢
  • 2010-11-14
  • 2015-02-12
  • 2014-04-19
  • 1970-01-01
  • 1970-01-01
  • 2011-01-11
  • 2013-05-10
  • 1970-01-01
  • 2013-11-14
相关资源
最近更新 更多