draw(_:) och drawRect — vad är det, anrop och överskrivning

Författare: IT Sectr Publicerad: 2026-07-20 Lästid: 7 min

draw(_:) / drawRect — är metoden i UIView-klassen (i Swift) och dess motsvarighet i Objective-C (drawRect:), som ansvarar för att rendera innehållet i vyn med Core Graphics. Systemet anropar denna metod automatiskt vid första visningen av vyn på skärmen och efter anrop av setNeedsDisplay(). Enligt Apple Documentation (2025) är draw(_:) den enda metoden där utvecklaren har tillgång till den aktuella skärmens grafikkontext för anpassad ritning. Överskrivning av draw(_:) ger full kontroll över komponentens utseende — från enkla geometriska former till komplex animerad grafik.

Huvudpunkter

  • draw(_:) — UIView-metod för anpassad ritning via Core Graphics, anropas inte direkt av utvecklaren
  • drawRect: — motsvarighet till draw(_:) i Objective-C, syntaktiskt annorlunda, funktionellt identisk
  • CGContext — grafikkontext tillgänglig inuti draw(_:) för alla ritoperationer
  • setNeedsDisplay() — det enda korrekta sättet att begära ett nytt anrop av draw(_:) från utvecklarens sida
  • UIGraphicsGetCurrentContext() — funktion för att hämta aktuell kontext inuti draw(_:), obligatoriskt steg före ritning

Vad är draw(_:) / drawRect

draw(_:) — är en instansmetod i UIView som UIKit anropar för att rendera innehållet i vyn. Inuti denna metod får utvecklaren tillgång till grafikkontexten CGContext och använder Core Graphics API för att rita linjer, fyllningar, text och bilder. drawRect: i Objective-C utför samma funktion, men med annan syntax: den enda parametern är en CGRect som anger området för omritning.

Enligt Apple Engineering (2024) fungerar draw(_:) genom CPU-rendering av Bitmap Graphics Context, vilket ger maximal flexibilitet men kräver mer resurser jämfört med CALayer. Beslutet att använda draw(_:) fattas baserat på grafikens komplexitet och prestandakrav.

Metodens signatur i Swift och Objective-C

I Swift deklareras metoden som override func draw(_ rect: CGRect), där rect är rektangeln som måste ritas om. I Objective-C är signaturen - (void)drawRect:(CGRect)rect. Parametern rect kan vara mindre än vyns bounds vid partiell omritning via setNeedsDisplay(_:).

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

När anropar systemet draw(_:)

Systemet anropar automatiskt draw(_:) i strikt definierade scenarier. Att förstå dessa triggers hjälper till att undvika onödig omritning och optimera vyns prestanda. Nedan listas alla fall av automatisk anropning av metoden.

  • Första renderingen — när vyn för första gången läggs till i hierarkin och blir synlig på skärmen
  • setNeedsDisplay() — efter anrop av denna metod av systemet vid närmaste ritcykel
  • setNeedsDisplay(_:) — samma, men med angivelse av specifik rektangel för omritning
  • contentMode — vid ändring av bounds, om contentMode kräver omritning (t.ex. .redraw)
  • setNeedsLayout() — i vissa fall kan omritning krävas efter omarrangering av subviews

Apple-dokumentationen varnar: anropa aldrig draw(_:) direkt. Systemet bestämmer själv när ritning ska utföras och direkt anrop stör den interna cachningsmekanismen. För att begära omritning, använd alltid setNeedsDisplay() eller setNeedsDisplay(_:).

Hur man överskriver draw(_:) i Swift

Att överskriva draw(_:) i Swift börjar med att hämta grafikkontexten och efterföljande Core Graphics-anrop. Det rekommenderas att skapa separata metoder för logiska ritblock — detta förbättrar kodens läsbarhet och testbarhet.

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

    guard let context = UIGraphicsGetCurrentContext() else { return }

    // Linjeparametrar
    context.setStrokeColor(UIColor.darkGray.cgColor)
    context.setLineWidth(2.0)

    // Rita en triangel
    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()
}

I detta exempel ritar draw(_:) en triangel med en mörkgrå kontur som är 2 pixlar tjock. Anrop av super.draw(rect) i början av metoden rekommenderas av Apple för att bevara förälderns ritlogik, även om standardimplementeringen av draw(_:) i UIView är tom.

Idempotensregeln för draw(_:)

Varje anrop av draw(_:) bör ge identiskt resultat vid samma indata. Detta gör det möjligt för systemet att cachelagra resultatet och inte anropa draw(_:) igen om vyns innehåll inte har ändrats. Använd inte slumpmässiga värden, systemtid eller nätverksförfrågningar inuti draw(_:).

drawRect: i Objective-C och skillnad från draw(_:)

drawRect: — historiskt den första versionen av metoden, som dök upp i iOS 2.0 tillsammans med Objective-C. I Swift döptes metoden om till draw(_:) med användning av den externa parametern _. Funktionellt är metoderna identiska: båda tar emot en CGRect för omritningsområdet och använder UIGraphicsGetCurrentContext() för att komma åt grafikkontexten.

Egenskapdraw(_:) (Swift)drawRect: (Objective-C)
Signaturoverride func draw(_ rect: CGRect)- (void)drawRect:(CGRect)rect
Super-anropsuper.draw(rect)[super drawRect:rect]
KontextUIGraphicsGetCurrentContext()UIGraphicsGetCurrentContext()
Parameter rectrect: CGRectCGRect rect
PrestandaIdentiskIdentisk

Vid migrering av ett projekt från Objective-C till Swift är omdöpning av metoden en av de första uppgifterna. Xcode tillhandahåller en automatisk omvandlare, men drawRect: kräver manuell uppdatering till draw(_:). Enligt Apple (2024) är Swift-versionen draw(_:) att föredra för nya projekt.

Optimering av ritning i draw(_:)

draw(_:) körs på CPU och en icke-optimal implementering kan orsaka bildrutebortfall och låg prestanda. Apple rekommenderar flera beprövade tillvägagångssätt för att påskynda ritningen.

Minimera antalet ritoperationer

Varje Core Graphics-operation (move(to:), addLine(to:), strokePath) har overhead. Gruppera operationer och använd CGPath för komplexa former — sökvägen skapas en gång och återanvänds vid varje anrop av draw(_:).

Använd UIBezierPath för vektorobjekt

UIBezierPath — är ett Objective-C-omslag runt CGPath som ger ett enkelt API för att skapa former. Skapa UIBezierPath i förväg (t.ex. i initieraren) och anropa helt enkelt fill() eller stroke() inuti draw(_:).

swift
private let starPath: UIBezierPath = {
    let path = UIBezierPath()
    // Bygga en stjärnform
    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()
}

Vanliga misstag vid arbete med draw(_:)

Utvecklare gör ofta samma misstag när de överskriver draw(_:). Kännedom om dessa mönster hjälper till att undvika buggar och prestandaförsämring. Låt oss titta på de vanligaste problemen och deras lösningar.

  • Direktanrop av draw(_:) — anropa aldrig draw(_:) direkt. Använd setNeedsDisplay() för att begära omritning. Direktanrop förstör cachning och kan leda till felaktig visning.
  • Tunga beräkningar inuti draw(_:) — draw(_:) bör vara så lätt som möjligt. Skapa UIBezierPath, bilder och andra tunga objekt utanför metoden, initiera dem en gång.
  • Skapa objekt inuti draw(_:) — konstruktioner av UIColor, UIFont och UIGraphicsImageRenderer inuti draw(_:) skapar extra minnesbelastning. Flytta objektskapandet till klassegenskaper.
  • Ignorera parametern rect — rect anger området som kräver omritning. Ritning utanför rect avvisas av systemet men förbrukar resurser. Kontrollera skärningen med rect före ritning.
  • Avsaknad av super.draw(rect) — även om UIView-implementeringen är tom rekommenderar Apple att anropa super.draw(rect) för kompatibilitet med framtida UIKit-ändringar.

Genom att följa dessa regler säkerställer du stabil och snabb ritning av anpassade vyer i alla iOS-projekt. Profilera draw(_:) via Instruments (Core Animation) för att se verklig exekveringstid och flaskhalsar.

Vanliga frågor

Kan man anropa draw(_:) direkt?

Nej, direkt anrop av draw(_:) är förbjudet enligt Apple-dokumentationen. Systemet hanterar själv ritcykeln. För att begära omritning, använd setNeedsDisplay(), som korrekt markerar vyn som behövande uppdatering i närmaste renderingscykel.

Vad skiljer drawRect: från draw(_:)?

Funktionellt är dessa metoder identiska. drawRect: används i Objective-C, draw(_:) — i Swift. Båda tar emot en CGRect för omritningsområdet och använder samma Core Graphics-kontext via UIGraphicsGetCurrentContext().

Varför anropas inte draw(_:) för en tom UIView?

Apple optimerar rendering: om UIView inte har en överskriven draw(_:) skapar systemet ingen bitmappskontext för den. Detta sparar minne. Om överskrivning finns men metoden inte anropas — kontrollera att vyens ram inte är noll och att vyn är synlig.

Hur ofta anropar systemet draw(_:)?

Endast vid behov: första renderingen, efter setNeedsDisplay(), vid ändring av bounds med contentMode = .redraw. I statiskt tillstånd anropas draw(_:) inte igen, vilket sparar CPU- och batteriresurser.

Måste man anropa super.draw(rect) i Swift?

Apple rekommenderar att anropa super.draw(rect) i början av den överskrivna metoden. Även om den nuvarande UIView-implementeringen är tom säkerställer super-anropet kompatibilitet med framtida versioner av UIKit och är god praxis.

Sammanfattning

  • draw(_:) / drawRect — den primära ritmetoden för UIView i Swift och Objective-C, anropas automatiskt av systemet
  • CGContext — Core Graphics-grafikkontexten tillgänglig i draw(_:) via UIGraphicsGetCurrentContext()
  • setNeedsDisplay() — korrekt sätt att begära omritning; direkt anrop av draw(_:) är förbjudet
  • Idempotens — draw(_:) bör ge samma resultat vid samma indata för korrekt cachning
  • UIBezierPath — skapa sökvägar utanför draw(_:) för att minimera CPU-belastning vid varje anrop
  • Parameter rect — innehåller omritningsområdet; använd skärning för optimering — rita inte utanför dess gränser
  • Profilering — kontrollera prestandan för draw(_:) via Instruments Core Animation för att upptäcka långsamma operationer

Vi utvecklar en mobil applikation nyckelfärdigt

IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.

Diskutera projektet

Läs också