2011-06-13 18 views
81

मैं ड्राइंग पथ के साथ खेल रहा था, और मैंने देखा कि कम से कम कुछ मामलों में, UIBezierPath जो मैंने सोचा था वह कोर ग्राफिक्स समकक्ष होगा। नीचे -drawRect: विधि दो पथ बनाता है: एक UIBezierPath, और एक 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]; 
} 

दोनों रास्तों 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 बना रहा हूं लग रहा है लेता है। मैं अपने सीजीपाथ ड्राइंग को तेज करने के लिए क्या कर सकता हूं?

+2

+1 काउंटर-सहज ज्ञान युक्त लगता है कि। –

+1

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

+4

'UIBezierPath'' CGPathRef' के चारों ओर एक रैपर है। क्या होगा यदि आप दोनों दस लाख बार कहते हैं, तो औसत लें, लेकिन संचालन के पहले और बाद में उपकरण का उपयोग न करें, लेकिन दो 'एनएसडीएटी' ऑब्जेक्ट्स का उपयोग न करें। –

उत्तर

142

आप सही हैं UIBezierPath कोर ग्राफिक्स के लिए एक उद्देश्य-सी रैपर है, और इसलिए तुलनात्मक रूप से प्रदर्शन करेगा। CGPath ड्राइंग करते समय UIBezierPath द्वारा सीधे उस सेटअप के लिए अंतर अलग है (और आपके प्रदर्शन डेल्टा का कारण) आपके CGContext स्थिति है।

  • lineWidth,
  • lineJoinStyle,
  • lineCapStyle,
  • miterLimit और
  • flatness

जब कॉल की जांच (disassembly: आप UIBezierPath को देखें, तो इसके लिए सेटिंग है) [path stroke], आप डब्ल्यू बीमार ध्यान दें कि यह CGContextStrokePath कॉल करने से पहले उन पिछले मानों के आधार पर वर्तमान ग्राफिक संदर्भ को कॉन्फ़िगर करता है। उपकरण से

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

स्नैपशॉट:: यदि आप अपने CGPath ड्राइंग के लिए एक ही पहले करते हैं, यह एक ही प्रदर्शन करेंगे Instruments snapshot showing equal performance

+5

इस पर ध्यान देने और इस तरह के स्पष्ट स्पष्टीकरण लिखने के लिए समय निकालने के लिए धन्यवाद। यह वास्तव में एक महान जवाब है। – Caleb

+1

कोई चिंता नहीं, खुशी ने –

+13

+1 को अटारी ब्रूस ली आइकन ... और संभवतः उत्तर के लिए मदद की। –

संबंधित मुद्दे