为什么UIBezierPath比Core Graphics路径更快? [英] Why is UIBezierPath faster than Core Graphics path?

查看:180
本文介绍了为什么UIBezierPath比Core Graphics路径更快?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I was playing around with drawing paths, and I noticed that in at least some cases, UIBezierPath outperforms what I thought would be a Core Graphics equivalent. The -drawRect: method below creates two paths: one UIBezierPath, and one CGPath. The paths are identical except for their locations, but stroking the CGPath takes roughly twice as long as stroking the 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];
}

两条路径都使用CGContextStrokePath(),所以我创建了单独的方法来描边每条路径这样我就可以看到仪器中每条路径的使用时间。以下是典型结果(呼叫树倒置);你可以看到 -strokeContext:需要9.5秒,而 -strokeUIBezierPath:只需要5秒:

Both paths use CGContextStrokePath(), so I created separate methods to stroke each path so that I can see the time used by each path in Instruments. Below are typical results (call tree inverted); you can see that -strokeContext: takes 9.5 sec., while -strokeUIBezierPath: takes only 5 sec.:

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:]

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

It looks like UIBezierPath is somehow optimizing the path that it creates, or I'm creating the CGPath in a naïve way. What can I do to speed up my CGPath drawing?

推荐答案

你是正确的 UIBezierPath 只是Core Graphics的一个Objective-c包装器,因此性能相当。直接绘制 CGPath 时,差异(以及性能增量的原因)是 CGContext 状态与由 UIBezierPath 设置。如果您查看 UIBezierPath ,它的设置为:

You are correct in that UIBezierPath is simply an objective-c wrapper for Core Graphics, and therefore will perform comparably. The difference (and reason for your performance delta) is your CGContext state when drawing your CGPath directly is quite different to that setup by UIBezierPath. If you look at UIBezierPath, it has settings for:


  • lineWidth

  • lineJoinStyle

  • lineCapStyle

  • miterLimit

  • 平坦度

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

检查电话(反汇编)为 [路径描边] ,您会注意到在执行 CGContextStrokePath 调用之前,它会根据这些先前的值配置当前图形上下文。如果在绘制CGPath之前执行相同的操作,它将执行相同的操作:

When examining the call (disassembly) to [path stroke], you will note that it configures the current graphic context based on those previous values before performing the CGContextStrokePath call. If you do the same prior to drawing your CGPath, it will perform the same:

- (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];
}

来自乐器的快照:

Snapshot from Instruments:

这篇关于为什么UIBezierPath比Core Graphics路径更快?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆