draw(_:) और drawRect — यह क्या है, कॉल और ओवरराइडिंग

लेखक: IT Sectr प्रकाशित: 2026-07-20 पढ़ने का समय: 7 मिनट

draw(_:) / drawRect UIView क्लास (Swift में) और Objective-C में इसके समकक्ष (drawRect:) की एक विधि है, जो Core Graphics का उपयोग करके व्यू की सामग्री को रेंडर करने के लिए जिम्मेदार है। सिस्टम इस विधि को स्वचालित रूप से कॉल करता है जब व्यू पहली बार स्क्रीन पर दिखाई देता है और setNeedsDisplay() कॉल करने के बाद। Apple Documentation (2025) के अनुसार, draw(_:) एकमात्र ऐसी विधि है जहाँ डेवलपर के पास कस्टम ड्राइंग के लिए वर्तमान स्क्रीन का ग्राफिक्स कॉन्टेक्स्ट उपलब्ध होता है। draw(_:) को ओवरराइड करना कॉम्पोनेंट की उपस्थिति पर पूर्ण नियंत्रण देता है — सरल ज्यामितीय आकृतियों से लेकर जटिल एनिमेटेड ग्राफिक्स तक।

मुख्य बिंदु

  • draw(_:) — Core Graphics के माध्यम से कस्टम ड्राइंग के लिए UIView विधि, डेवलपर द्वारा सीधे कॉल नहीं की जाती
  • drawRect: — Objective-C में draw(_:) का समकक्ष, सिंटैक्स में भिन्न, कार्यात्मक रूप से समान
  • CGContext — सभी ड्राइंग संचालन के लिए draw(_:) के अंदर उपलब्ध ग्राफिक्स कॉन्टेक्स्ट
  • setNeedsDisplay() — डेवलपर की ओर से draw(_:) का पुनः ड्राइंग अनुरोध करने का एकमात्र सही तरीका
  • UIGraphicsGetCurrentContext() — draw(_:) के अंदर वर्तमान कॉन्टेक्स्ट प्राप्त करने का फंक्शन, ड्राइंग से पहले अनिवार्य कदम

draw(_:) / drawRect क्या है

draw(_:) UIView की एक इंस्टेंस विधि है जिसे UIKit व्यू की सामग्री रेंडर करने के लिए कॉल करता है। इस विधि के अंदर, डेवलपर को CGContext ग्राफिक्स कॉन्टेक्स्ट तक पहुँच मिलती है और वह लाइनें, भरण, टेक्स्ट और इमेज बनाने के लिए Core Graphics API का उपयोग करता है। Objective-C में drawRect: समान कार्य करता है लेकिन भिन्न सिंटैक्स के साथ: एकमात्र पैरामीटर एक CGRect है जो पुनः ड्राइंग क्षेत्र निर्दिष्ट करता है।

Apple Engineering (2024) के अनुसार, draw(_:) CPU-आधारित Bitmap Graphics Context रेंडरिंग के माध्यम से काम करता है, जो अधिकतम लचीलापन प्रदान करता है लेकिन CALayer की तुलना में अधिक संसाधनों की आवश्यकता होती है। draw(_:) का उपयोग करने का निर्णय ग्राफिक्स की जटिलता और प्रदर्शन आवश्यकताओं के आधार पर लिया जाता है।

Swift और Objective-C में विधि हस्ताक्षर

Swift में, विधि को override func draw(_ rect: CGRect) के रूप में घोषित किया जाता है, जहाँ rect वह आयत है जिसे पुनः बनाने की आवश्यकता है। Objective-C में हस्ताक्षर - (void)drawRect:(CGRect)rect है। setNeedsDisplay(_:) के माध्यम से आंशिक पुनः ड्राइंग के दौरान rect पैरामीटर व्यू के bounds से छोटा हो सकता है।

objective-c
- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
    CGContextFillRect(context, rect);
}

सिस्टम draw(_:) को कब कॉल करता है

सिस्टम स्वचालित रूप से draw(_:) को कड़ाई से परिभाषित परिदृश्यों में कॉल करता है। इन ट्रिगर्स को समझने से अनावश्यक पुनः ड्राइंग से बचने और व्यू प्रदर्शन को अनुकूलित करने में मदद मिलती है। नीचे विधि के स्वचालित कॉल के सभी मामले सूचीबद्ध हैं।

  • पहला रेंडर — जब व्यू पहली बार पदानुक्रम में जोड़ा जाता है और स्क्रीन पर दिखाई देता है
  • setNeedsDisplay() — इस विधि को कॉल करने के बाद, सिस्टम अगले ड्राइंग चक्र में पुनः बनाता है
  • setNeedsDisplay(_:) — उपरोक्त के समान, लेकिन पुनः ड्राइंग के लिए एक विशिष्ट आयत निर्दिष्ट करता है
  • contentMode — जब bounds बदलते हैं, यदि contentMode को पुनः ड्राइंग की आवश्यकता होती है (जैसे .redraw)
  • setNeedsLayout() — कुछ मामलों में, सबव्यू पुनर्व्यवस्था के बाद, पुनः ड्राइंग आवश्यक हो सकती है

Apple दस्तावेज़ चेतावनी देता है: draw(_:) को सीधे कभी न कॉल करें। सिस्टम स्वयं तय करता है कि ड्राइंग कब करनी है, और सीधा कॉल आंतरिक कैशिंग तंत्र को बाधित करता है। पुनः ड्राइंग का अनुरोध करने के लिए, हमेशा setNeedsDisplay() या setNeedsDisplay(_:) का उपयोग करें।

Swift में draw(_:) को कैसे ओवरराइड करें

Swift में draw(_:) को ओवरराइड करना ग्राफिक्स कॉन्टेक्स्ट प्राप्त करने और उसके बाद Core Graphics कॉल के साथ शुरू होता है। ड्राइंग के तार्किक ब्लॉकों के लिए अलग-अलग विधियाँ बनाने की अनुशंसा की जाती है — इससे कोड पठनीयता और परीक्षण क्षमता में सुधार होता है।

swift
override func draw(_ rect: CGRect) {
    super.draw(rect)

    guard let context = UIGraphicsGetCurrentContext() else { return }

    // Line parameters
    context.setStrokeColor(UIColor.darkGray.cgColor)
    context.setLineWidth(2.0)

    // Drawing a triangle
    context.move(to: CGPoint(x: rect.midX, y: rect.minY + 10))
    context.addLine(to: CGPoint(x: rect.maxX - 10, y: rect.maxY - 10))
    context.addLine(to: CGPoint(x: rect.minX + 10, y: rect.maxY - 10))
    context.closePath()
    context.strokePath()
}

इस उदाहरण में, draw(_:) 2 पिक्सेल मोटी गहरे भूरे रंग की रूपरेखा के साथ एक त्रिभुज बनाता है। Apple द्वारा विधि की शुरुआत में super.draw(rect) कॉल करने की अनुशंसा की जाती है ताकि पैरेंट ड्राइंग तर्क संरक्षित रहे, हालाँकि UIView का डिफ़ॉल्ट draw(_:) कार्यान्वयन खाली है।

draw(_:) का इडेम्पोटेंसी नियम

draw(_:) का प्रत्येक कॉल समान इनपुट डेटा के साथ समान परिणाम देना चाहिए। यह सिस्टम को परिणाम कैश करने की अनुमति देता है और यदि व्यू की सामग्री नहीं बदली है तो draw(_:) को दोबारा कॉल नहीं करता। उपयोग न करें draw(_:) के अंदर यादृच्छिक मान, सिस्टम समय या नेटवर्क अनुरोध।

Objective-C में drawRect: और draw(_:) से अंतर

drawRect: ऐतिहासिक रूप से विधि का पहला संस्करण है, जो iOS 2.0 में Objective-C के साथ प्रकट हुआ। Swift में, विधि का नाम बदलकर draw(_:) कर दिया गया जिसमें बाहरी पैरामीटर _ का उपयोग किया गया। कार्यात्मक रूप से, विधियाँ समान हैं: दोनों पुनः ड्राइंग क्षेत्र का CGRect प्राप्त करती हैं और ग्राफिक्स कॉन्टेक्स्ट तक पहुँचने के लिए UIGraphicsGetCurrentContext() का उपयोग करती हैं।

विशेषताdraw(_:) (Swift)drawRect: (Objective-C)
हस्ताक्षरoverride func draw(_ rect: CGRect)- (void)drawRect:(CGRect)rect
super कॉलsuper.draw(rect)[super drawRect:rect]
कॉन्टेक्स्टUIGraphicsGetCurrentContext()UIGraphicsGetCurrentContext()
rect पैरामीटरrect: CGRectCGRect rect
प्रदर्शनसमानसमान

Objective-C से Swift में प्रोजेक्ट माइग्रेट करते समय, विधि का नाम बदलना पहले कार्यों में से एक है। Xcode एक स्वचालित कनवर्टर प्रदान करता है, लेकिन drawRect: को मैन्युअल रूप से draw(_:) में अपडेट करने की आवश्यकता होती है। Apple (2024) के अनुसार, Swift संस्करण draw(_:) नए प्रोजेक्ट्स के लिए प्राथमिकता है।

draw(_:) में ड्राइंग का अनुकूलन

draw(_:) CPU पर चलता है, और एक सबऑप्टिमल कार्यान्वयन फ्रेम ड्रॉप और खराब प्रदर्शन का कारण बन सकता है। Apple ड्राइंग को गति देने के लिए कई सिद्ध दृष्टिकोणों की अनुशंसा करता है।

ड्राइंग संचालन की संख्या कम करें

प्रत्येक Core Graphics संचालन (move(to:), addLine(to:), strokePath) में ओवरहेड होता है। संचालन को समूहित करें और जटिल आकृतियों के लिए CGPath का उपयोग करें — पथ एक बार बनाया जाता है और प्रत्येक draw(_:) कॉल पर पुनः उपयोग किया जाता है।

वेक्टर ऑब्जेक्ट्स के लिए UIBezierPath का उपयोग करें

UIBezierPath CGPath पर एक Objective-C रैपर है जो आकृतियाँ बनाने के लिए एक सरल API प्रदान करता है। UIBezierPath को पहले से बनाएँ (उदाहरण के लिए, इनिशियलाइज़र में) और draw(_:) के अंदर बस fill() या stroke() कॉल करें।

swift
private let starPath: UIBezierPath = {
    let path = UIBezierPath()
    // Building a star shape
    path.move(to: CGPoint(x: 50, y: 0))
    for i in 1...5 {
        let angle = CGFloat(i) * 4 * CGFloat.pi / 5
        path.addLine(to: CGPoint(x: 50 + 40 * cos(angle),
                               y: 50 + 40 * sin(angle)))
    }
    path.close()
    return path
}()

override func draw(_ rect: CGRect) {
    UIColor.systemYellow.setFill()
    starPath.fill()
}

draw(_:) के साथ काम करते समय सामान्य गलतियाँ

डेवलपर अक्सर draw(_:) को ओवरराइड करते समय समान गलतियाँ करते हैं। इन पैटर्न को जानने से बग और प्रदर्शन में गिरावट से बचने में मदद मिलती है। आइए सबसे सामान्य समस्याओं और उनके समाधानों पर नज़र डालें।

  • draw(_:) का सीधा कॉल — draw(_:) को सीधे कभी न कॉल करें। पुनः ड्राइंग का अनुरोध करने के लिए setNeedsDisplay() का उपयोग करें। सीधा कॉल कैशिंग को तोड़ता है और गलत प्रदर्शन का कारण बन सकता है।
  • draw(_:) के अंदर भारी गणना — draw(_:) जितना संभव हो उतना हल्का होना चाहिए। UIBezierPath, इमेज और अन्य भारी ऑब्जेक्ट को विधि के बाहर बनाएँ, उन्हें एक बार इनिशियलाइज़ करें।
  • draw(_:) के अंदर ऑब्जेक्ट बनाना — draw(_:) के अंदर UIColor, UIFont और UIGraphicsImageRenderer निर्माण मेमोरी पर अनावश्यक भार बनाते हैं। ऑब्जेक्ट निर्माण को क्लास प्रॉपर्टी में ले जाएँ।
  • rect पैरामीटर को अनदेखा करना — rect उस क्षेत्र को निर्दिष्ट करता है जिसे पुनः बनाने की आवश्यकता है। rect के बाहर ड्राइंग सिस्टम द्वारा छोड़ दी जाती है लेकिन संसाधनों का उपयोग करती है। ड्राइंग से पहले rect के साथ इंटरसेक्शन की जाँच करें।
  • super.draw(rect) की कमी — हालाँकि UIView का कार्यान्वयन खाली है, Apple भविष्य के UIKit परिवर्तनों के साथ संगतता के लिए super.draw(rect) कॉल करने की अनुशंसा करता है।

इन नियमों का पालन करके, आप किसी भी iOS प्रोजेक्ट में स्थिर और तेज़ कस्टम व्यू ड्राइंग सुनिश्चित करेंगे। वास्तविक निष्पादन समय और बाधाओं को देखने के लिए Instruments (Core Animation) के माध्यम से draw(_:) को प्रोफ़ाइल करें।

अक्सर पूछे जाने वाले प्रश्न

क्या draw(_:) को सीधे कॉल किया जा सकता है?

नहीं, draw(_:) का सीधा कॉल Apple दस्तावेज़ द्वारा निषिद्ध है। सिस्टम स्वयं ड्राइंग चक्र प्रबंधित करता है। पुनः ड्राइंग का अनुरोध करने के लिए setNeedsDisplay() का उपयोग करें, जो निकटतम रेंडरिंग चक्र में व्यू को अपडेट की आवश्यकता के रूप में सही ढंग से चिह्नित करता है।

drawRect: draw(_:) से कैसे भिन्न है?

कार्यात्मक रूप से ये विधियाँ समान हैं। drawRect: Objective-C में उपयोग किया जाता है, draw(_:) Swift में। दोनों पुनः ड्राइंग क्षेत्र का CGRect प्राप्त करते हैं और UIGraphicsGetCurrentContext() के माध्यम से समान Core Graphics कॉन्टेक्स्ट का उपयोग करते हैं।

खाली UIView के लिए draw(_:) क्यों नहीं कॉल किया जाता?

Apple रेंडरिंग को अनुकूलित करता है: यदि UIView में कोई ओवरराइडेड draw(_:) नहीं है, तो सिस्टम इसके लिए bitmap कॉन्टेक्स्ट नहीं बनाता। इससे मेमोरी बचती है। यदि ओवरराइड मौजूद है लेकिन विधि कॉल नहीं होती — जाँच करें कि व्यू का फ्रेम गैर-शून्य है और व्यू दृश्यमान है।

सिस्टम कितनी बार draw(_:) को कॉल करता है?

केवल आवश्यकता होने पर: पहला रेंडर, setNeedsDisplay() के बाद, contentMode = .redraw के साथ bounds बदलने पर। स्थिर अवस्था में, draw(_:) दोबारा कॉल नहीं किया जाता, जिससे CPU और बैटरी संसाधनों की बचत होती है।

क्या Swift में super.draw(rect) कॉल करना आवश्यक है?

Apple ओवरराइडेड विधि की शुरुआत में super.draw(rect) कॉल करने की अनुशंसा करता है। हालाँकि वर्तमान UIView कार्यान्वयन खाली है, super कॉल भविष्य के UIKit संस्करणों के साथ संगतता सुनिश्चित करता है और एक अच्छी प्रथा है।

सारांश

  • draw(_:) / drawRect — Swift और Objective-C में UIView की मुख्य ड्राइंग विधि, सिस्टम द्वारा स्वचालित रूप से कॉल की जाती है
  • CGContext — UIGraphicsGetCurrentContext() के माध्यम से draw(_:) के अंदर उपलब्ध Core Graphics कॉन्टेक्स्ट
  • setNeedsDisplay() — पुनः ड्राइंग का अनुरोध करने का सही तरीका; draw(_:) का सीधा कॉल निषिद्ध है
  • इडेम्पोटेंसी — उचित कैशिंग के लिए draw(_:) को समान इनपुट डेटा के साथ समान परिणाम देना चाहिए
  • UIBezierPath — प्रत्येक कॉल पर CPU लोड कम करने के लिए draw(_:) के बाहर पथ बनाएँ
  • rect पैरामीटर — इसमें पुनः ड्राइंग क्षेत्र होता है; अनुकूलन के लिए इंटरसेक्शन का उपयोग करें — इसके बाहर न बनाएँ
  • प्रोफ़ाइलिंग — धीमे संचालन की पहचान करने के लिए Instruments Core Animation के माध्यम से draw(_:) प्रदर्शन की जाँच करें

हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे

IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।

परियोजना पर चर्चा करें

यह भी पढ़ें