draw(_:) és drawRect — mi ez, meghívás és felülbírálás

Szerző: IT Sectr Megjelenés: 2026-07-20 Olvasási idő: 7 perc

draw(_:) / drawRect — ez a UIView osztály metódusa (Swift-ben) és annak analógja Objective-C-ben (drawRect:), amely a nézet tartalmának Core Graphics segítségével történő megjelenítéséért felelős. A rendszer automatikusan meghívja ezt a metódust a nézet első képernyőn történő megjelenésekor és a setNeedsDisplay() meghívása után. Az Apple Documentation (2025) szerint a draw(_:) az egyetlen metódus, ahol a fejlesztő hozzáfér az aktuális képernyő grafikus kontextusához egyedi rajzoláshoz. A draw(_:) felülbírálása teljes irányítást ad a komponens megjelenése felett — az egyszerű geometriai alakzatoktól a bonyolult animált grafikáig.

Főbb pontok

  • draw(_:) — UIView metódus egyedi rajzoláshoz Core Graphics-on keresztül, nem hívható meg közvetlenül a fejlesztő által
  • drawRect: — a draw(_:) megfelelője Objective-C-ben, szintaktikailag különbözik, funkcionálisan azonos
  • CGContext — grafikus kontextus, amely a draw(_:) belsejében érhető el minden rajzolási művelethez
  • setNeedsDisplay() — az egyetlen helyes mód a draw(_:) ismételt meghívásának kérésére a fejlesztő részéről
  • UIGraphicsGetCurrentContext() — függvény az aktuális kontextus lekérésére a draw(_:) belsejében, kötelező lépés a rajzolás előtt

Mi az a draw(_:) / drawRect

draw(_:) — egy UIView példánymetódus, amelyet a UIKit hív meg a nézet tartalmának megjelenítéséhez. A metódus belsejében a fejlesztő hozzáfér a CGContext grafikus kontextushoz, és a Core Graphics API-t használja vonalak, kitöltések, szövegek és képek rajzolásához. A drawRect: Objective-C-ben ugyanazt a funkciót látja el, de eltérő szintaxissal: az egyetlen paraméter egy CGRect, amely az újrarajzolandó területet adja meg.

Az Apple Engineering (2024) szerint a draw(_:) CPU-megjelenítésen, Bitmap Graphics Context-en keresztül működik, ami maximális rugalmasságot biztosít, de több erőforrást igényel a CALayer-hez képest. A draw(_:) használatáról szóló döntést a grafika összetettsége és a teljesítménykövetelmények alapján hozzák meg.

A metódus aláírása Swift-ben és Objective-C-ben

Swift-ben a metódus override func draw(_ rect: CGRect) formában van deklarálva, ahol rect az újrarajzolandó téglalap. Objective-C-ben az aláírás - (void)drawRect:(CGRect)rect. A rect paraméter kisebb lehet a nézet bounds-ánál részleges újrarajzolás esetén a setNeedsDisplay(_:) híváson keresztül.

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

Mikor hívja meg a rendszer a draw(_:)-t

A rendszer automatikusan meghívja a draw(_:)-t szigorúan meghatározott forgatókönyvekben. Ezen triggerek megértése segít elkerülni a felesleges újrarajzolásokat és optimalizálni a nézet teljesítményét. Az alábbiakban felsoroljuk a metódus automatikus meghívásának összes esetét.

  • Első megjelenítés — amikor a nézet először kerül hozzáadásra a hierarchiához és láthatóvá válik a képernyőn
  • setNeedsDisplay() — e metódus meghívása után a rendszer által a legközelebbi rajzolási ciklusban
  • setNeedsDisplay(_:) — ugyanaz, de az újrarajzolandó konkrét téglalap megadásával
  • contentMode — a bounds megváltozásakor, ha a contentMode újrarajzolást igényel (pl. .redraw)
  • setNeedsLayout() — bizonyos esetekben az alnézetek átrendezése után újrarajzolásra lehet szükség

Az Apple dokumentációja figyelmeztet: soha ne hívd meg közvetlenül a draw(_:)-t. A rendszer maga dönti el, mikor végezze el a rajzolást, és a közvetlen hívás megzavarja a belső gyorsítótárazási mechanizmust. Az újrarajzolás kéréséhez mindig a setNeedsDisplay() vagy a setNeedsDisplay(_:) használata javasolt.

Hogyan bíráljuk felül a draw(_:)-t Swift-ben

A draw(_:) felülbírálása Swift-ben a grafikus kontextus lekérésével és az azt követő Core Graphics hívásokkal kezdődik. Javasolt külön metódusokat létrehozni a rajzolás logikai blokkjaihoz — ez javítja a kód olvashatóságát és tesztelhetőségét.

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

    guard let context = UIGraphicsGetCurrentContext() else { return }

    // Vonal paraméterei
    context.setStrokeColor(UIColor.darkGray.cgColor)
    context.setLineWidth(2.0)

    // Háromszög rajzolása
    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()
}

Ebben a példában a draw(_:) egy háromszöget rajzol 2 pixel vastag sötétszürke körvonallal. A super.draw(rect) hívása a metódus elején az Apple által javasolt a szülő rajzolási logikájának megőrzése érdekében, bár a UIView alapértelmezett draw(_:) implementációja üres.

A draw(_:) idempotencia szabálya

A draw(_:) minden hívásának azonos bemeneti adatok mellett azonos eredményt kell adnia. Ez lehetővé teszi a rendszer számára, hogy gyorsítótárazza az eredményt, és ne hívja meg újra a draw(_:)-t, ha a nézet tartalma nem változott. Ne használj a draw(_:) belsejében véletlenszerű értékeket, rendszeridőt vagy hálózati kéréseket.

drawRect: Objective-C-ben és különbség a draw(_:)-től

drawRect: — történetileg a metódus első változata, amely az iOS 2.0-ban jelent meg az Objective-C-vel együtt. Swift-ben a metódust draw(_:)-re nevezték át a _ külső paraméter használatával. Funkcionálisan a metódusok azonosak: mindkettő megkapja az újrarajzolandó terület CGRect-jét, és a UIGraphicsGetCurrentContext() segítségével éri el a grafikus kontextust.

Jellemződraw(_:) (Swift)drawRect: (Objective-C)
Aláírásoverride func draw(_ rect: CGRect)- (void)drawRect:(CGRect)rect
Super hívássuper.draw(rect)[super drawRect:rect]
KontextusUIGraphicsGetCurrentContext()UIGraphicsGetCurrentContext()
Paraméter rectrect: CGRectCGRect rect
TeljesítményAzonosAzonos

A projekt Objective-C-ről Swift-re történő migrálásakor a metódus átnevezése az egyik első feladat. Az Xcode automatikus konvertert biztosít, de a drawRect: kézi frissítést igényel draw(_:)-re. Az Apple (2024) szerint a Swift draw(_:) változata előnyösebb az új projektekhez.

Rajzolás optimalizálása a draw(_:)-ben

A draw(_:) CPU-n fut, és a nem optimális implementáció képkocka-kiesést és alacsony teljesítményt okozhat. Az Apple több bevált megközelítést javasol a rajzolás felgyorsításához.

Minimalizáld a rajzolási műveletek számát

Minden Core Graphics műveletnek (move(to:), addLine(to:), strokePath) van többletköltsége. Csoportosítsd a műveleteket, és használj CGPath-t összetett alakzatokhoz — az útvonal egyszer jön létre, és minden draw(_:) híváskor újra felhasználható.

Használj UIBezierPath-t vektoros objektumokhoz

UIBezierPath — egy Objective-C burkoló a CGPath körül, amely egyszerű API-t biztosít alakzatok létrehozásához. Hozd létre a UIBezierPath-t előre (pl. az inicializátorban), és egyszerűen hívd meg a fill() vagy stroke() metódust a draw(_:) belsejében.

swift
private let starPath: UIBezierPath = {
    let path = UIBezierPath()
    // Csillag alakzat létrehozása
    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()
}

Gyakori hibák a draw(_:) használatakor

A fejlesztők gyakran ugyanazokat a hibákat követik el a draw(_:) felülbírálásakor. Ezen minták ismerete segít elkerülni a hibákat és a teljesítmény romlását. Tekintsük át a leggyakoribb problémákat és megoldásaikat.

  • A draw(_:) közvetlen meghívása — soha ne hívd meg közvetlenül a draw(_:)-t. Használd a setNeedsDisplay()-t az újrarajzolás kéréséhez. A közvetlen hívás tönkreteszi a gyorsítótárazást és helytelen megjelenítéshez vezethet.
  • Nehéz számítások a draw(_:) belsejében — a draw(_:) legyen a lehető legkönnyebb. Hozd létre a UIBezierPath-ot, képeket és más nehéz objektumokat a metóduson kívül, inicializáld őket egyszer.
  • Objektumok létrehozása a draw(_:) belsejében — UIColor, UIFont és UIGraphicsImageRenderer konstrukciók a draw(_:) belsejében többlet memóriaterhelést okoznak. Helyezd át az objektumlétrehozást az osztály tulajdonságaiba.
  • A rect paraméter figyelmen kívül hagyása — a rect azt a területet jelöli, amely újrarajzolást igényel. A rect-en kívüli rajzolást a rendszer elveti, de erőforrásokat fogyaszt. Ellenőrizd a metszetet a rect-el rajzolás előtt.
  • A super.draw(rect) hiánya — bár a UIView implementációja üres, az Apple javasolja a super.draw(rect) meghívását a jövőbeli UIKit változásokkal való kompatibilitás érdekében.

E szabályok betartásával stabil és gyors egyedi nézetek rajzolását biztosíthatod bármely iOS projektben. Profilozd a draw(_:)-t az Instruments (Core Animation) segítségével, hogy lásd a tényleges végrehajtási időt és a szűk keresztmetszeteket.

Gyakran Ismételt Kérdések

Meghívható-e közvetlenül a draw(_:)?

Nem, a draw(_:) közvetlen meghívása tilos az Apple dokumentációja szerint. A rendszer maga kezeli a rajzolási ciklust. Az újrarajzolás kéréséhez használd a setNeedsDisplay()-t, amely helyesen jelöli meg a nézetet frissítendőként a legközelebbi renderelési ciklusban.

Miben különbözik a drawRect: a draw(_:)-től?

Funkcionálisan ezek a metódusok azonosak. A drawRect: Objective-C-ben használatos, a draw(_:) — Swift-ben. Mindkettő megkapja az újrarajzolandó terület CGRect-jét, és ugyanazt a Core Graphics kontextust használja a UIGraphicsGetCurrentContext() segítségével.

Miért nem hívódik meg a draw(_:) üres UIView esetén?

Az Apple optimalizálja a renderelést: ha a UIView-nek nincs felülbírált draw(_:)-je, a rendszer nem hoz létre bitmap kontextust számára. Ez memóriát takarít meg. Ha a felülbírálás létezik, de a metódus nem hívódik meg — ellenőrizd, hogy a nézet kerete nem nulla-e és a nézet látható-e.

Milyen gyakran hívja meg a rendszer a draw(_:)-t?

Csak szükség esetén: első renderelés, setNeedsDisplay() után, bounds változásakor contentMode = .redraw esetén. Statikus állapotban a draw(_:) nem hívódik meg újra, ami CPU-t és akkumulátort takarít meg.

Meg kell hívni a super.draw(rect)-et Swift-ben?

Az Apple javasolja a super.draw(rect) meghívását a felülbírált metódus elején. Bár a UIView jelenlegi implementációja üres, a super hívás biztosítja a kompatibilitást a jövőbeli UIKit verziókkal, és jó gyakorlat.

Összefoglaló

  • draw(_:) / drawRect — a UIView fő rajzolási metódusa Swift-ben és Objective-C-ben, automatikusan hívja a rendszer
  • CGContext — a Core Graphics grafikus kontextus, amely a draw(_:) belsejében érhető el a UIGraphicsGetCurrentContext()-en keresztül
  • setNeedsDisplay() — a helyes mód az újrarajzolás kérésére; a draw(_:) közvetlen hívása tilos
  • Idempotencia — a draw(_:) azonos bemenetre azonos eredményt adjon a helyes gyorsítótárazáshoz
  • UIBezierPath — hozd létre az útvonalakat a draw(_:) kívül, hogy minimalizáld a CPU terhelést minden híváskor
  • Paraméter rect — tartalmazza az újrarajzolandó területet; használj intersection-t optimalizáláshoz — ne rajzolj a határain kívül
  • Profilozás — ellenőrizd a draw(_:) teljesítményét az Instruments Core Animation segítségével a lassú műveletek felderítéséhez

Kulcsrakész mobilalkalmazást fejlesztünk

Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.

Projekt megbeszélése

Olvassa el is