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(_:) 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.
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.
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
CGContextFillRect(context, rect);
}
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.
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(_:).
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.
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.
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: 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.
| Eigenschaft | draw(_:) (Swift) | drawRect: (Objective-C) |
|---|---|---|
| Signatur | override func draw(_ rect: CGRect) | - (void)drawRect:(CGRect)rect |
| super-Aufruf | super.draw(rect) | [super drawRect:rect] |
| Kontext | UIGraphicsGetCurrentContext() | UIGraphicsGetCurrentContext() |
| Parameter rect | rect: CGRect | CGRect rect |
| Leistung | Identisch | Identisch |
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.
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.
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.
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.
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()
}
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.
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
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.
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().
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.
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.
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
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.
Lesen Sie auch