为什么UIBezierPath比Core Graphics路径更快?

Cal*_*leb 87 iphone bezier drawing ios

我正在玩绘图路径,我注意到至少在某些情况下,UIBezierPath优于我认为的Core Graphics等价物.-drawRect:下面的方法创建两个路径:一个UIBezierPath和一个CGPath.除了它们的位置之外,路径是相同的,但是抚摸CGPath所需的时间大约是抚摸UIBezierPath的两倍.

- (void)drawRect:(CGRect)rect
{
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    // Create the two paths, cgpath and uipath.
    CGMutablePathRef cgpath = CGPathCreateMutable();
    CGPathMoveToPoint(cgpath, NULL, 0, 100);

    UIBezierPath *uipath = [[UIBezierPath alloc] init];
    [uipath moveToPoint:CGPointMake(0, 200)];

    // Add 200 curve segments to each path.
    int iterations = 200;
    CGFloat cgBaseline = 100;
    CGFloat uiBaseline = 200;
    CGFloat xincrement = self.bounds.size.width / iterations;
    for (CGFloat x1 = 0, x2 = xincrement;
         x2 < self.bounds.size.width;
         x1 = x2, x2 += xincrement)
    {
        CGPathAddCurveToPoint(cgpath, NULL, x1, cgBaseline-50, x2, cgBaseline+50, x2, cgBaseline);
        [uipath addCurveToPoint:CGPointMake(x2, uiBaseline)
                  controlPoint1:CGPointMake(x1, uiBaseline-50)
                  controlPoint2:CGPointMake(x2, uiBaseline+50)];
    }
    [[UIColor blackColor] setStroke];
    CGContextAddPath(ctx, cgpath);

    // Stroke each path.
    [self strokeContext:ctx];
    [self strokeUIBezierPath:uipath];

    [uipath release];
    CGPathRelease(cgpath);
}

- (void)strokeContext:(CGContextRef)context
{
    CGContextStrokePath(context);
}

- (void)strokeUIBezierPath:(UIBezierPath*)path
{
    [path stroke];
}
Run Code Online (Sandbox Code Playgroud)

两个路径都使用CGContextStrokePath(),因此我创建了单独的方法来描边每个路径,以便我可以看到Instruments中每个路径使用的时间.以下是典型结果(呼叫树倒置); 你可以看到-strokeContext:需要9.5秒,而-strokeUIBezierPath:只需要5秒:

Running (Self)      Symbol Name
14638.0ms   88.2%               CGContextStrokePath
9587.0ms   57.8%                 -[QuartzTestView strokeContext:]
5051.0ms   30.4%                 -[UIBezierPath stroke]
5051.0ms   30.4%                  -[QuartzTestView strokeUIBezierPath:]
Run Code Online (Sandbox Code Playgroud)

看起来UIBezierPath在某种程度上优化了它创建的路径,或者我是以天真的方式创建CGPath.我该怎么做才能加快我的CGPath绘图速度?

Stu*_*nie 150

你是对的,UIBezierPath它只是Core Graphics的一个Objective-c包装器,因此性能相当.差异(以及您的性能增量的原因)是CGContextCGPath直接绘制时的状态与设置完全不同UIBezierPath.如果你看一下UIBezierPath,它有以下设置:

  • lineWidth,
  • lineJoinStyle,
  • lineCapStyle,
  • miterLimit
  • flatness

在检查调用(反汇编)时[path stroke],您将注意到它在执行CGContextStrokePath调用之前根据这些先前的值配置当前图形上下文.如果在绘制CGPath之前执行相同操作,它将执行相同的操作:

- (void)drawRect:(CGRect)rect
{
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    // Create the two paths, cgpath and uipath.
    CGMutablePathRef cgpath = CGPathCreateMutable();
    CGPathMoveToPoint(cgpath, NULL, 0, 100);

    UIBezierPath *uipath = [[UIBezierPath alloc] init];
    [uipath moveToPoint:CGPointMake(0, 200)];

    // Add 200 curve segments to each path.
    int iterations = 80000;
    CGFloat cgBaseline = 100;
    CGFloat uiBaseline = 200;
    CGFloat xincrement = self.bounds.size.width / iterations;
    for (CGFloat x1 = 0, x2 = xincrement;
         x2 < self.bounds.size.width;
         x1 = x2, x2 += xincrement)
    {
        CGPathAddCurveToPoint(cgpath, NULL, x1, cgBaseline-50, x2, cgBaseline+50, x2, cgBaseline);
        [uipath addCurveToPoint:CGPointMake(x2, uiBaseline)
                  controlPoint1:CGPointMake(x1, uiBaseline-50)
                  controlPoint2:CGPointMake(x2, uiBaseline+50)];
    }
    [[UIColor blackColor] setStroke];
    CGContextAddPath(ctx, cgpath);

    // Stroke each path
    CGContextSaveGState(ctx); {
        // configure context the same as uipath
        CGContextSetLineWidth(ctx, uipath.lineWidth);
        CGContextSetLineJoin(ctx, uipath.lineJoinStyle);
        CGContextSetLineCap(ctx, uipath.lineCapStyle);
        CGContextSetMiterLimit(ctx, uipath.miterLimit);
        CGContextSetFlatness(ctx, uipath.flatness);
        [self strokeContext:ctx];
        CGContextRestoreGState(ctx);
    }
    [self strokeUIBezierPath:uipath];

    [uipath release];
    CGPathRelease(cgpath);
}

- (void)strokeContext:(CGContextRef)context
{
    CGContextStrokePath(context);
}

- (void)strokeUIBezierPath:(UIBezierPath*)path
{
    [path stroke];
}
Run Code Online (Sandbox Code Playgroud)

仪器快照: 仪器快照显示相同的性能

  • atari bruce lee图标+1,可能还有答案. (14认同)
  • 感谢您抽出时间研究并撰写如此清晰的解释.这真是一个很好的答案. (6认同)
  • 所以... 2x性能差异是一个或多个cgcontext设置 - 例如,可能是这样的:"lineWidth 2.0表现比lineWidth 1.0差"......? (5认同)
  • @Adam,是的 (2认同)
  • FWIW我总是发现1.0的线宽是最快的 - 我的假设是因为宽度> 1px时,缓和成为一个问题. (2认同)