draw(_:) at drawRect — ano ito, tawag at override

May-akda: IT Sectr Nai-publish: 2026-07-20 Oras ng pagbabasa: 7 min

draw(_:) / drawRect — ito ang metodo ng UIView class (sa Swift) at ang katumbas nito sa Objective-C (drawRect:), na responsable sa pag-render ng nilalaman ng view gamit ang Core Graphics. Awtomatikong tinatawag ng system ang metodong ito sa unang paglitaw ng view sa screen at pagkatapos ng pagtawag sa setNeedsDisplay(). Ayon sa Apple Documentation (2025), ang draw(_:) ay ang tanging metodo kung saan ang developer ay may access sa graphic context ng kasalukuyang screen para sa custom na pagguhit. Ang pag-override ng draw(_:) ay nagbibigay ng buong kontrol sa hitsura ng component — mula sa simpleng geometric na hugis hanggang sa kumplikadong animated na graphics.

Mga Pangunahing Punto

  • draw(_:) — metodo ng UIView para sa custom na pagguhit sa pamamagitan ng Core Graphics, hindi direktang tinatawag ng developer
  • drawRect: — katumbas ng draw(_:) sa Objective-C, magkaiba ang syntax, magkapareho ang function
  • CGContext — graphic context na available sa loob ng draw(_:) para sa lahat ng operasyon sa pagguhit
  • setNeedsDisplay() — ang tanging tamang paraan upang humiling ng muling pagtawag sa draw(_:) mula sa developer
  • UIGraphicsGetCurrentContext() — function para makuha ang kasalukuyang context sa loob ng draw(_:), mandatoryong hakbang bago gumuhit

Ano ang draw(_:) / drawRect

draw(_:) — ay isang instance method ng UIView na tinatawag ng UIKit para i-render ang nilalaman ng view. Sa loob ng metodong ito, ang developer ay nakakakuha ng access sa graphic context na CGContext at ginagamit ang Core Graphics API para gumuhit ng mga linya, fill, text, at mga imahe. Ang drawRect: sa Objective-C ay gumagawa ng parehong function, ngunit may ibang syntax: ang tanging parameter ay CGRect na tumutukoy sa area na muling iguguhit.

Ayon sa Apple Engineering (2024), ang draw(_:) ay gumagana sa pamamagitan ng CPU-rendering Bitmap Graphics Context, na nagbibigay ng maximum na flexibility, ngunit nangangailangan ng mas maraming resources kumpara sa CALayer. Ang desisyon na gamitin ang draw(_:) ay ginagawa batay sa pagiging kumplikado ng graphics at mga kinakailangan sa performance.

Signature ng metodo sa Swift at Objective-C

Sa Swift, ang metodo ay idineklara bilang override func draw(_ rect: CGRect), kung saan ang rect ay ang rectangle na kailangang muling iguhit. Sa Objective-C ang signature ay - (void)drawRect:(CGRect)rect. Ang parameter na rect ay maaaring mas maliit kaysa sa bounds ng view sa bahagyang muling pagguhit sa pamamagitan ng setNeedsDisplay(_:).

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

Kailan tinatawag ng system ang draw(_:)

Awtomatikong tinatawag ng system ang draw(_:) sa mahigpit na tinukoy na mga senaryo. Ang pag-unawa sa mga trigger na ito ay tumutulong upang maiwasan ang hindi kinakailangang muling pagguhit at i-optimize ang performance ng view. Sa ibaba ay nakalista ang lahat ng kaso ng awtomatikong pagtawag ng metodo.

  • Unang render — kapag ang view ay unang idinagdag sa hierarchy at naging nakikita sa screen
  • setNeedsDisplay() — pagkatapos ng pagtawag sa metodong ito ng system sa pinakamalapit na cycle ng pagguhit
  • setNeedsDisplay(_:) — pareho, ngunit may pagtukoy ng specific rectangle para muling iguhit
  • contentMode — kapag nagbago ang bounds, kung ang contentMode ay nangangailangan ng muling pagguhit (hal. .redraw)
  • setNeedsLayout() — sa ilang kaso pagkatapos ng muling pag-aayos ng subviews ay maaaring kailanganin ang muling pagguhit

Ang dokumentasyon ng Apple ay nagbabala: huwag kailanman tawagin nang direkta ang draw(_:). Ang system mismo ang nagpapasya kung kailan isasagawa ang pagguhit, at ang direktang pagtawag ay sumisira sa internal caching mechanism. Para humiling ng muling pagguhit, palaging gamitin ang setNeedsDisplay() o setNeedsDisplay(_:).

Paano i-override ang draw(_:) sa Swift

Ang pag-override ng draw(_:) sa Swift ay nagsisimula sa pagkuha ng graphic context at mga sumusunod na pagtawag sa Core Graphics. Inirerekomenda na gumawa ng hiwalay na mga metodo para sa logical na bloke ng pagguhit — pinapabuti nito ang pagiging madaling basahin at testability ng code.

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

    guard let context = UIGraphicsGetCurrentContext() else { return }

    // Mga parameter ng linya
    context.setStrokeColor(UIColor.darkGray.cgColor)
    context.setLineWidth(2.0)

    // Pagguhit ng tatsulok
    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()
}

Sa halimbawang ito, ang draw(_:) ay gumuhit ng tatsulok na may dark gray na outline na 2 pixels ang kapal. Ang pagtawag sa super.draw(rect) sa simula ng metodo ay inirerekomenda ng Apple upang mapanatili ang parent drawing logic, kahit na ang default na implementasyon ng draw(_:) sa UIView ay walang laman.

Rule ng idempotency ng draw(_:)

Ang bawat pagtawag sa draw(_:) ay dapat magbigay ng magkaparehong resulta sa parehong input data. Ito ay nagpapahintulot sa system na i-cache ang resulta at hindi na tawagin muli ang draw(_:) kung ang nilalaman ng view ay hindi nagbago. Huwag gamitin sa loob ng draw(_:) ang random na halaga, oras ng system, o network requests.

drawRect: sa Objective-C at pagkakaiba sa draw(_:)

drawRect: — historikal na unang bersyon ng metodo, lumitaw sa iOS 2.0 kasama ng Objective-C. Sa Swift, ang metodo ay pinalitan ng pangalan sa draw(_:) na may paggamit ng external parameter na _. Functional na magkapareho ang mga metodo: pareho silang tumatanggap ng CGRect ng area na muling iguguhit at ginagamit ang UIGraphicsGetCurrentContext() para ma-access ang graphic context.

Katangiandraw(_:) (Swift)drawRect: (Objective-C)
Signatureoverride func draw(_ rect: CGRect)- (void)drawRect:(CGRect)rect
Pagtawag ng supersuper.draw(rect)[super drawRect:rect]
ContextUIGraphicsGetCurrentContext()UIGraphicsGetCurrentContext()
Parameter rectrect: CGRectCGRect rect
PerformanceMagkaparehoMagkapareho

Sa pag-migrate ng proyekto mula Objective-C patungong Swift, ang pagpapalit ng pangalan ng metodo ay isa sa mga unang gawain. Ang Xcode ay nagbibigay ng automatic converter, ngunit ang drawRect: ay nangangailangan ng manual na pag-update sa draw(_:). Ayon sa Apple (2024), ang Swift version na draw(_:) ay mas gusto para sa mga bagong proyekto.

Pag-optimize ng pagguhit sa draw(_:)

Ang draw(_:) ay isinasagawa sa CPU, at ang hindi optimal na implementasyon ay maaaring maging sanhi ng pagbaba ng frame at mababang performance. Ang Apple ay nagre-rekomenda ng ilang napatunayang approach para mapabilis ang pagguhit.

Bawasan ang bilang ng drawing operations

Ang bawat operasyon ng Core Graphics (move(to:), addLine(to:), strokePath) ay may overhead. I-grupo ang mga operasyon at gamitin ang CGPath para sa kumplikadong mga hugis — ang path ay ginagawa nang isang beses at ginagamit muli sa bawat pagtawag ng draw(_:).

Gamitin ang UIBezierPath para sa vector objects

UIBezierPath — ay isang Objective-C wrapper sa paligid ng CGPath na nagbibigay ng simpleng API para sa paggawa ng mga hugis. Gumawa ng UIBezierPath nang maaga (hal. sa initializer) at tawagin lamang ang fill() o stroke() sa loob ng draw(_:).

swift
private let starPath: UIBezierPath = {
    let path = UIBezierPath()
    // Pagbuo ng hugis bituin
    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()
}

Mga karaniwang pagkakamali sa paggamit ng draw(_:)

Ang mga developer ay madalas na gumagawa ng parehong pagkakamali sa pag-override ng draw(_:). Ang kaalaman sa mga pattern na ito ay tumutulong upang maiwasan ang mga bug at pagbaba ng performance. Tingnan natin ang mga pinakakaraniwang problema at ang kanilang mga solusyon.

  • Direktang pagtawag sa draw(_:) — huwag kailanman tawagin nang direkta ang draw(_:). Gamitin ang setNeedsDisplay() para humiling ng muling pagguhit. Ang direktang pagtawag ay sumisira sa caching at maaaring humantong sa maling display.
  • Mabibigat na kalkulasyon sa loob ng draw(_:) — ang draw(_:) ay dapat na gaan hangga't maaari. Gumawa ng UIBezierPath, mga imahe, at iba pang mabibigat na bagay sa labas ng metodo, i-initialize ang mga ito nang isang beses.
  • Paggawa ng mga bagay sa loob ng draw(_:) — ang mga konstruksyon ng UIColor, UIFont, at UIGraphicsImageRenderer sa loob ng draw(_:) ay lumilikha ng dagdag na memory load. Ilipat ang paggawa ng bagay sa mga property ng klase.
  • Hindi pagpansin sa parameter na rect — ang rect ay nagpapahiwatig ng area na nangangailangan ng muling pagguhit. Ang pagguhit sa labas ng rect ay tinatanggihan ng system, ngunit gumagamit ng resources. Suriin ang intersection sa rect bago gumuhit.
  • Kawalan ng super.draw(rect) — kahit na ang implementasyon ng UIView ay walang laman, inirerekomenda ng Apple ang pagtawag ng super.draw(rect) para sa compatibility sa hinaharap na pagbabago ng UIKit.

Sa pagsunod sa mga panuntunang ito, masisiguro mo ang matatag at mabilis na pagguhit ng custom na views sa anumang iOS project. I-profile ang draw(_:) sa pamamagitan ng Instruments (Core Animation) upang makita ang aktwal na oras ng execution at mga bottleneck.

Mga Madalas Itanong

Maaari bang direktang tawagin ang draw(_:)?

Hindi, ang direktang pagtawag sa draw(_:) ay ipinagbabawal ng dokumentasyon ng Apple. Ang system mismo ang namamahala sa drawing cycle. Para humiling ng muling pagguhit, gamitin ang setNeedsDisplay(), na wastong nagmamarka ng view bilang nangangailangan ng update sa pinakamalapit na rendering cycle.

Paano naiiba ang drawRect: sa draw(_:)?

Functional na magkapareho ang mga metodong ito. Ang drawRect: ay ginagamit sa Objective-C, ang draw(_:) — sa Swift. Pareho silang tumatanggap ng CGRect ng muling pagguhit na area at gumagamit ng parehong Core Graphics context sa pamamagitan ng UIGraphicsGetCurrentContext().

Bakit hindi tinatawag ang draw(_:) para sa walang laman na UIView?

Ino-optimize ng Apple ang rendering: kung ang UIView ay walang naka-override na draw(_:), hindi gumagawa ang system ng bitmap context para dito. Ito ay nakakatipid ng memory. Kung mayroong override ngunit hindi tinatawag ang metodo — suriin na ang frame ng view ay hindi zero at ang view ay nakikita.

Gaano kadalas tinatawag ng system ang draw(_:)?

Kapag kailangan lamang: unang rendering, pagkatapos ng setNeedsDisplay(), kapag nagbago ang bounds na may contentMode = .redraw. Sa static na estado, hindi na muling tinatawag ang draw(_:), na nakakatipid ng CPU at baterya.

Kailangan bang tawagin ang super.draw(rect) sa Swift?

Inirerekomenda ng Apple na tawagin ang super.draw(rect) sa simula ng naka-override na metodo. Kahit na ang kasalukuyang implementasyon ng UIView ay walang laman, ang super call ay nagsisiguro ng compatibility sa hinaharap na bersyon ng UIKit at ito ay mabuting kasanayan.

Buod

  • draw(_:) / drawRect — pangunahing drawing method ng UIView sa Swift at Objective-C, awtomatikong tinatawag ng system
  • CGContext — Core Graphics graphic context na available sa draw(_:) sa pamamagitan ng UIGraphicsGetCurrentContext()
  • setNeedsDisplay() — tamang paraan upang humiling ng muling pagguhit; direktang pagtawag sa draw(_:) ay ipinagbabawal
  • Idempotency — ang draw(_:) ay dapat magbigay ng parehong resulta sa parehong input para sa tamang caching
  • UIBezierPath — gumawa ng mga path sa labas ng draw(_:) upang mabawasan ang CPU load sa bawat pagtawag
  • Parameter rect — naglalaman ng muling pagguhit na area; gamitin ang intersection para sa optimization — huwag gumuhit sa labas ng hangganan nito
  • Profiling — suriin ang performance ng draw(_:) sa pamamagitan ng Instruments Core Animation para matukoy ang mabagal na operasyon

Gagawa kami ng mobile application na turnkey

Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.

Pag-usapan ang proyekto

Basahin din