draw(_:) und drawRect — was es ist, Aufruf und Überschreibung

Autor: IT Sectr Veröffentlicht: 2026-07-20 Lesezeit: 7 Min.

draw(_:) / drawRect ist eine Methode der UIView-Klasse (in Swift) und ihr Gegenstück in Objective-C (drawRect:), die für die Darstellung des View-Inhalts mit Core Graphics verantwortlich ist. Das System ruft diese Methode automatisch auf, wenn die View zum ersten Mal auf dem Bildschirm erscheint und nach dem Aufruf von setNeedsDisplay(). Laut Apple Documentation (2025) ist draw(_:) die einzige Methode, bei der der Entwickler Zugriff auf den Grafik-Kontext des aktuellen Bildschirms für benutzerdefinierte Zeichnungen hat. Das Überschreiben von draw(_:) gibt volle Kontrolle über das Erscheinungsbild der Komponente — von einfachen geometrischen Formen bis hin zu komplexen animierten Grafiken.

Wichtige Punkte

  • draw(_:) — UIView-Methode für benutzerdefinierte Zeichnungen über Core Graphics, wird nicht direkt vom Entwickler aufgerufen
  • drawRect: — Entsprechung von draw(_:) in Objective-C, syntaktisch unterschiedlich, funktional identisch
  • CGContext — Grafik-Kontext, der innerhalb von draw(_:) für alle Zeichenoperationen verfügbar ist
  • setNeedsDisplay() — die einzig korrekte Methode, um ein erneutes Zeichnen von draw(_:) durch den Entwickler anzufordern
  • UIGraphicsGetCurrentContext() — Funktion zum Abrufen des aktuellen Kontexts innerhalb von draw(_:), obligatorischer Schritt vor dem Zeichnen

Was ist draw(_:) / drawRect

draw(_:) ist eine Instanzmethode von UIView, die UIKit aufruft, um den Inhalt der View zu rendern. Innerhalb dieser Methode erhält der Entwickler Zugriff auf den CGContext-Grafikkontext und verwendet die Core Graphics API zum Zeichnen von Linien, Füllungen, Text und Bildern. drawRect: in Objective-C erfüllt die gleiche Funktion, jedoch mit anderer Syntax: der einzige Parameter ist ein CGRect, das den neu zu zeichnenden Bereich angibt.

Laut Apple Engineering (2024) arbeitet draw(_:) über CPU-basiertes Bitmap Graphics Context Rendering, was maximale Flexibilität bietet, aber im Vergleich zu CALayer mehr Ressourcen benötigt. Die Entscheidung für draw(_:) wird basierend auf der Komplexität der Grafik und den Leistungsanforderungen getroffen.

Methodensignatur in Swift und Objective-C

In Swift wird die Methode als override func draw(_ rect: CGRect) deklariert, wobei rect das Rechteck ist, das neu gezeichnet werden muss. In Objective-C lautet die Signatur - (void)drawRect:(CGRect)rect. Der Parameter rect kann bei teilweisem Neuzeichnen über setNeedsDisplay(_:) kleiner als die bounds der View sein.

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

Wann ruft das System draw(_:) auf

Das System ruft draw(_:) automatisch in streng definierten Szenarien auf. Das Verständnis dieser Auslöser hilft, unnötiges Neuzeichnen zu vermeiden und die Leistung der View zu optimieren. Nachfolgend sind alle Fälle des automatischen Methodenaufrufs aufgeführt.

  • Erstes Rendern — wenn die View zum ersten Mal zur Hierarchie hinzugefügt und auf dem Bildschirm sichtbar wird
  • setNeedsDisplay() — nach dem Aufruf dieser Methode zeichnet das System beim nächsten Zeichenzyklus neu
  • setNeedsDisplay(_:) — wie oben, aber mit Angabe eines bestimmten Rechtecks für das Neuzeichnen
  • contentMode — bei Änderung der bounds, wenn contentMode ein Neuzeichnen erfordert (z.B. .redraw)
  • setNeedsLayout() — in einigen Fällen kann nach der Neuanordnung von Subviews ein Neuzeichnen erforderlich sein

Die Apple-Dokumentation warnt: Rufen Sie draw(_:) niemals direkt auf. Das System entscheidet selbst, wann es zeichnet, und ein direkter Aufruf stört den internen Caching-Mechanismus. Verwenden Sie zum Anfordern eines Neuzeichnens immer setNeedsDisplay() oder setNeedsDisplay(_:).

Wie man draw(_:) in Swift überschreibt

Das Überschreiben von draw(_:) in Swift beginnt mit dem Abrufen des Grafik-Kontexts und anschließenden Aufrufen von Core Graphics. Es wird empfohlen, separate Methoden für logische Zeichenblöcke zu erstellen — dies verbessert die Lesbarkeit und Testbarkeit des Codes.

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()
}

In diesem Beispiel zeichnet draw(_:) ein Dreieck mit einem 2 Pixel dicken dunkelgrauen Umriss. Der Aufruf von super.draw(rect) zu Beginn der Methode wird von Apple empfohlen, um die übergeordnete Zeichenlogik zu erhalten, obwohl die Standardimplementierung von draw(_:) in UIView leer ist.

Die Idempotenz-Regel von draw(_:)

Jeder Aufruf von draw(_:) sollte bei gleichen Eingabedaten ein identisches Ergebnis liefern. Dies ermöglicht es dem System, das Ergebnis zwischenzuspeichern und draw(_:) nicht erneut aufzurufen, wenn sich der Inhalt der View nicht geändert hat. Verwenden Sie innerhalb von draw(_:) keine Zufallswerte, Systemzeit oder Netzwerkanfragen.

drawRect: in Objective-C und Unterschiede zu draw(_:)

drawRect: ist historisch die erste Version der Methode, die mit iOS 2.0 und Objective-C eingeführt wurde. In Swift wurde die Methode unter Verwendung des externen Parameters _ in draw(_:) umbenannt. Funktionell sind die Methoden identisch: Beide erhalten ein CGRect des neu zu zeichnenden Bereichs und verwenden UIGraphicsGetCurrentContext() für den Zugriff auf den Grafik-Kontext.

Eigenschaftdraw(_:) (Swift)drawRect: (Objective-C)
Signaturoverride func draw(_ rect: CGRect)- (void)drawRect:(CGRect)rect
super-Aufrufsuper.draw(rect)[super drawRect:rect]
KontextUIGraphicsGetCurrentContext()UIGraphicsGetCurrentContext()
Parameter rectrect: CGRectCGRect rect
LeistungIdentischIdentisch

Bei der Migration eines Projekts von Objective-C zu Swift ist die Umbenennung der Methode eine der ersten Aufgaben. Xcode bietet einen automatischen Konverter, aber drawRect: erfordert eine manuelle Aktualisierung auf draw(_:). Laut Apple (2024) ist die Swift-Version draw(_:) für neue Projekte zu bevorzugen.

Optimierung der Zeichnung in draw(_:)

draw(_:) wird auf der CPU ausgeführt, und eine suboptimale Implementierung kann zu Bildwiederholungsaussetzern und schlechter Leistung führen. Apple empfiehlt mehrere bewährte Ansätze zur Beschleunigung der Zeichnung.

Minimieren Sie die Anzahl der Zeichenoperationen

Jede Core Graphics-Operation (move(to:), addLine(to:), strokePath) verursacht Overhead. Gruppieren Sie Operationen und verwenden Sie CGPath für komplexe Formen — der Pfad wird einmal erstellt und bei jedem draw(_:)-Aufruf wiederverwendet.

Verwenden Sie UIBezierPath für Vektorobjekte

UIBezierPath ist ein Objective-C-Wrapper um CGPath, der eine einfache API zum Erstellen von Formen bietet. Erstellen Sie UIBezierPath im Voraus (z.B. im Initialisierer) und rufen Sie einfach fill() oder stroke() innerhalb von draw(_:) auf.

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()
}

Häufige Fehler bei der Arbeit mit draw(_:)

Entwickler machen beim Überschreiben von draw(_:) oft die gleichen Fehler. Die Kenntnis dieser Muster hilft, Fehler und Leistungseinbußen zu vermeiden. Sehen wir uns die häufigsten Probleme und ihre Lösungen an.

  • Direkter Aufruf von draw(_:) — rufen Sie draw(_:) niemals direkt auf. Verwenden Sie setNeedsDisplay(), um ein Neuzeichnen anzufordern. Ein direkter Aufruf zerstört das Caching und kann zu falscher Darstellung führen.
  • Schwere Berechnungen innerhalb von draw(_:) — draw(_:) sollte so leichtgewichtig wie möglich sein. Erstellen Sie UIBezierPath, Bilder und andere schwere Objekte außerhalb der Methode und initialisieren Sie sie einmal.
  • Objekterstellung innerhalb von draw(_:) — Konstruktionen von UIColor, UIFont und UIGraphicsImageRenderer innerhalb von draw(_:) erzeugen unnötige Speicherbelastung. Verschieben Sie die Objekterstellung in Klasseneigenschaften.
  • Ignorieren des rect-Parameters — rect gibt den Bereich an, der neu gezeichnet werden muss. Das Zeichnen außerhalb von rect wird vom System verworfen, verbraucht aber Ressourcen. Überprüfen Sie vor dem Zeichnen die Überschneidung mit rect.
  • Fehlender super.draw(rect)-Aufruf — obwohl die UIView-Implementierung leer ist, empfiehlt Apple den Aufruf von super.draw(rect) für die Kompatibilität mit zukünftigen UIKit-Änderungen.

Wenn Sie diese Regeln befolgen, gewährleisten Sie stabiles und schnelles benutzerdefiniertes Zeichnen von Views in jedem iOS-Projekt. Profilen Sie draw(_:) mit Instruments (Core Animation), um die tatsächliche Ausführungszeit und Engpässe zu sehen.

Häufig gestellte Fragen

Kann man draw(_:) direkt aufrufen?

Nein, der direkte Aufruf von draw(_:) ist durch die Apple-Dokumentation verboten. Das System verwaltet den Zeichenzyklus selbst. Verwenden Sie zum Anfordern eines Neuzeichnens setNeedsDisplay(), das die View korrekt als aktualisierungsbedürftig im nächsten Renderzyklus markiert.

Wie unterscheidet sich drawRect: von draw(_:)?

Funktionell sind diese Methoden identisch. drawRect: wird in Objective-C verwendet, draw(_:) in Swift. Beide erhalten ein CGRect des neu zu zeichnenden Bereichs und verwenden denselben Core Graphics-Kontext über UIGraphicsGetCurrentContext().

Warum wird draw(_:) für eine leere UIView nicht aufgerufen?

Apple optimiert das Rendering: Wenn eine UIView kein überschriebenes draw(_:) hat, erstellt das System keinen Bitmap-Kontext dafür. Das spart Speicher. Wenn die Überschreibung existiert, die Methode aber nicht aufgerufen wird — überprüfen Sie, ob der Frame der View nicht Null und die View sichtbar ist.

Wie oft ruft das System draw(_:) auf?

Nur bei Bedarf: erstes Rendern, nach setNeedsDisplay(), bei Änderung der bounds mit contentMode = .redraw. Im statischen Zustand wird draw(_:) nicht erneut aufgerufen, was CPU- und Batterieressourcen schont.

Muss man super.draw(rect) in Swift aufrufen?

Apple empfiehlt, super.draw(rect) am Anfang der überschriebenen Methode aufzurufen. Obwohl die aktuelle UIView-Implementierung leer ist, gewährleistet der super-Aufruf die Kompatibilität mit zukünftigen UIKit-Versionen und ist eine gute Praxis.

Zusammenfassung

  • draw(_:) / drawRect — die wichtigste Zeichenmethode von UIView in Swift und Objective-C, automatisch vom System aufgerufen
  • CGContext — Core Graphics-Kontext, verfügbar innerhalb von draw(_:) über UIGraphicsGetCurrentContext()
  • setNeedsDisplay() — der korrekte Weg, ein Neuzeichnen anzufordern; direkter Aufruf von draw(_:) ist verboten
  • Idempotenz — draw(_:) sollte bei gleichen Eingabedaten das gleiche Ergebnis liefern für korrektes Caching
  • UIBezierPath — erstellen Sie Pfade außerhalb von draw(_:), um die CPU-Last bei jedem Aufruf zu minimieren
  • Parameter rect — enthält den Neuzeichnungsbereich; verwenden Sie Überschneidung zur Optimierung — zeichnen Sie nicht außerhalb
  • Profiling — überprüfen Sie die Leistung von draw(_:) mit Instruments Core Animation, um langsame Operationen zu identifizieren

Wir entwickeln eine mobile Applikation schlüsselfertig

IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.

Projekt besprechen

Lesen Sie auch