UIBezierPath कोर ग्राफिक्स पथ से अधिक तेज़ क्यों है?


90

मैं ड्राइंग पथों के साथ खेल रहा था, और मैंने देखा कि कम से कम कुछ मामलों में, UIBezierPath ने मुझे लगता है कि कोर ग्राफिक्स समकक्ष होगा। -drawRect:एक UIBezierPath, और एक CGPath: नीचे दी गई विधि दो रास्ते बनाता है। रास्ते अपने स्थानों को छोड़कर समान हैं, लेकिन CGPath को पथपाकर UIBezPath को पथपाकर के रूप में लगभग दो बार लेता है।

- (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 सेकंड लगते हैं।:

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 ड्राइंग को गति देने के लिए क्या कर सकता हूं?


2
+1 जो लगता है कि काउंटर-इंट्रस्टिंग है।
ग्रैडी प्लेयर

1
मैंने आमतौर पर कोरग्राफिक्स को बहुत धीमा पाया है जब रेखाएं, रास्ते वगैरह खींचते हैं। मुझे पता नहीं क्यों लेकिन मुझे ज्यादातर ओपनजीएल में जाना पड़ता है या कुशल ड्राइंग के लिए कोकोस 2 डी का उपयोग करना पड़ता है। निश्चित रूप से मैं समझता हूं कि यह तेज़ है, लेकिन मुझे वास्तव में यह समझ में नहीं आता है कि सीजी इतना धीमा क्यों है, यह देखते हुए कि इसे ओपनजीएल का ही उपयोग करना चाहिए।
अच्युत

4
UIBezierPathचारों ओर एक आवरण है CGPathRef। क्या होगा अगर आप दोनों कहते हैं, दस मिलियन बार, तो औसत लें, लेकिन NSDateसंचालन से पहले और बाद में इंस्ट्रूमेंट्स का उपयोग न करें लेकिन दो वस्तुओं का उपयोग करें ।

1
@TP, परिणाम डिवाइस और सिम्युलेटर में सुसंगत हैं और यह नहीं बदलते हैं कि क्या -drawRect:कुछ दर्जन बार या कुछ सौ कहा जाता है। मैंने इसे सिम्युलेटर पर 80000 से अधिक वक्र खंडों (डिवाइस के लिए बहुत अधिक) के साथ आज़माया है। परिणाम हमेशा लगभग एक जैसे होते हैं: CGPath UIBezierPath से लगभग दो बार लेता है, भले ही दोनों CGContextStrokePath () को ड्रा करने के लिए उपयोग करते हैं। यह स्पष्ट प्रतीत होता है कि UIBezierPath जिस पथ का निर्माण करता है, वह CGPathAddCurveToPoint () के साथ निर्मित किसी भी तरह से अधिक कुशल है। मैं यह जानना चाहता हूं कि UIBezierPath जैसे कुशल पथ का निर्माण कैसे किया जाता है।
कालेब

जवाबों:


154

आप सही हैं कि UIBezierPathकोर ग्राफिक्स के लिए बस एक उद्देश्य-सी आवरण है, और इसलिए तुलनात्मक रूप से प्रदर्शन करेंगे। अंतर और (आपके प्रदर्शन डेल्टा का कारण) आपकी CGContextस्थिति है जब आपका CGPathसीधे ड्राइंग उस सेटअप द्वारा काफी भिन्न होता है 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];
}

उपकरण से स्नैपशॉट: उपकरण स्नैपशॉट समान प्रदर्शन दिखा रहा है


6
इस पर गौर करने और इस तरह की स्पष्ट व्याख्या लिखने के लिए धन्यवाद। यह वाकई एक बेहतरीन जवाब है।
कालेब

14
+1 अटारी ब्रूस ली आइकन के लिए ... और संभवतः उत्तर के लिए।
ग्रैडी प्लेयर

5
तो ... 2x प्रदर्शन अंतर cgcontext सेटिंग्स में से एक या अधिक था - उदाहरण के लिए शायद कुछ इस तरह: "2.0 की लाइनवाइट, 1.0 की लाइनवाइट से भी बदतर प्रदर्शन करती है ..."?
एडम

2
FWIW मैं हमेशा 1.0 की लाइन चौड़ाई पाया है सबसे तेज - मेरी धारणा है क्योंकि mitering चौड़ाई> 1px के लिए एक मुद्दा बन जाता है।
मार्क आफलिक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.