ProgrammierungSenior iOS Entwickler

Was sind 'opaque types' (some) in Swift, wann und warum werden sie verwendet, und wie unterscheiden sie sich von Protokollen mit associated type?

Bestehen Sie Vorstellungsgespräche mit dem Hintsage-KI-Assistenten

Antwort.

Geschichte des Themas:

In Swift bis Version 5 gab es beim Zurückgeben eines Wertes, der einem Protokoll mit associated type entspricht, häufig Einschränkungen — der Typ konnte nicht direkt als Rückgabetyp verwendet werden, es war Type Erasure erforderlich. Um die Lesbarkeit und Leistung zu verbessern, wurden opaque types eingeführt — Rückgabewerte über das Schlüsselwort some, die es ermöglichen, Abstraktionen in öffentlichen Schnittstellen zu beschreiben.

Problem:

Wenn man den tatsächlichen Typ des zurückgegebenen Wertes verbergen möchte, während man die Abstraktion über ein Protokoll beibehält, aber die Kosten von dynamic dispatch und type erasure vermeiden möchte. Zum Beispiel beim Zurückgeben von Sammlungen, Sequenzen, View-Komponenten.

Lösung:

Opaque types ermöglichen es, einen Typ, der einem Protokoll entspricht, zurückzugeben, während seine konkrete Implementierung verborgen bleibt. Der Compiler kennt den tatsächlichen Typ, aber die aufrufende Seite nicht.

Beispiel:

protocol Shape { func area() -> Double } struct Circle: Shape { var radius: Double func area() -> Double { Double.pi * radius * radius } } func makeCircle() -> some Shape { return Circle(radius: 3) } let s = makeCircle() print(s.area()) // funktioniert

Wichtige Merkmale:

  • Opaque type — immer derselbe Typ, der hinter dem Protokoll verborgen ist, definiert im Rückgabewert über some
  • Schneller und strenger als type erasure, ermöglicht die Arbeit mit associated type in Protokollen
  • Erlaubt nicht, unterschiedliche Typen in verschiedenen Zweigen zurückzugeben (der Typ muss für alle Rückgaben gleich sein)

Fangfragen.

Wie unterscheidet sich opaque type (some Protocol) vom Rückgabetyp Protocol?

Opaque type hat zur Compile-Zeit eine konkrete Implementierung (obwohl sie von außen verborgen ist). Bei der Rückgabe von Protocol wird dynamic dispatch angewendet, es gibt keine type safety, wenn ein associated type vorhanden ist.

Kann man unterschiedliche Typen mit some Protocol in einer Funktion zurückgeben?

Nein. Alle Rückgaben müssen denselben tatsächlichen Typ zurückgeben:

func maker(flag: Bool) -> some Shape { if flag { return Circle(radius: 3) } else { return Square(size: 2) // Fehler: Rückgabetyp stimmt nicht überein } }

Kann associatedtype innerhalb von Protocol über some Protocol verwendet werden?

Ja. Genau dafür (vor allem) ist opaque type gedacht:

protocol View { associatedtype Body } func makeView() -> some View { /* ... */ }

Typische Fehler und Anti-Patterns

  • Verwirrung zwischen some Protocol und Protocol — unterschiedliche Fälle und Einschränkungen
  • Verletzung der Homogenitätsregel des Rückgabetyps in allen Zweigen
  • Verwendung von some, wo es einfacher wäre, protocol oder typealias zu verwenden

Beispiel aus dem Leben

Negativer Fall

Die Funktion gibt ein Protokoll ohne opaque zurück, was die Verwendung von Methoden mit associated type nicht erlaubt, komplizierte type erasure erforderlich macht, der Code kompiliert nicht oder arbeitet suboptimal.

Vorteile:

  • Flexibilität in Abstraktionen wie AnySequence

Nachteile:

  • Verlust der type safety, niedrige Leistung
  • Associated types funktionieren nicht

Positiver Fall

ViewBuilder in SwiftUI verwendet some View und verbirgt Details, erhöht die Typensicherheit, verbessert die Kompilierungsgeschwindigkeit und Runtime.

Vorteile:

  • Lesbare API, type safety, kein dynamic dispatch
  • Einfachheit in der Wartung

Nachteile:

  • Es können keine unterschiedlichen Typen in einer Funktion zurückgegeben werden