ProgrammatieSenior iOS ontwikkelaar

Wat zijn 'opaque types' (some) in Swift, wanneer en waarom deze te gebruiken, en hoe verschillen ze van protocols met associated types?

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord.

Geschiedenis van de vraag:

In Swift tot versie 5 stuitte men bij het teruggeven van een waarde die overeenkomt met een protocol met associated type vaak op beperkingen — het type kon niet rechtstreeks als return type worden gebruikt, type erasure was nodig. Om de leesbaarheid en prestaties te verbeteren, zijn opaque types geïntroduceerd — teruggegeven waarden via het sleutelwoord some, waarmee abstracties in publieke interfaces kunnen worden beschreven.

Probleem:

Wanneer het nodig is om het echte type van het teruggegeven resultaat te verbergen, terwijl de abstractie via een protocol behouden blijft, maar tegelijkertijd de kosten van dynamic dispatch en type erasure te vermijden. Bijvoorbeeld, bij het teruggeven van collecties, sequenties, view-componenten.

Oplossing:

Opaque types maken het mogelijk om een type dat aan een protocol voldoet terug te geven, waarbij de specifieke implementatie ervan verborgen blijft. De compiler kent het echte type, maar de aanroepende zijde niet.

Voorbeeld:

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()) // werkt

Belangrijke kenmerken:

  • Opaque type — altijd hetzelfde type, verborgen achter een protocol, verklaard in de return via some
  • Sneller en strikter dan type erasure, staat toe te werken met associated types in protocols
  • Staat niet toe verschillende types te retourneren in verschillende vertakkingen (het type moet hetzelfde zijn voor alle returns)

Vragen met een valstrik.

Hoe verschilt opaque type (some Protocol) van het geretourneerde type Protocol?

Opaque type heeft bij compilatie een specifieke implementatie (hoewel deze van buitenaf verborgen is). Bij het retourneren van Protocol werkt dynamic dispatch, is er geen type safety als er associated types zijn.

Kan ik verschillende types retourneren met behulp van some Protocol in één functie?

Nee. Alle return-statements moeten hetzelfde echte type retourneren:

func maker(flag: Bool) -> some Shape { if flag { return Circle(radius: 3) } else { return Square(size: 2) // Fout: return type komt niet overeen } }

Kan associatedtype binnen een Protocol worden gebruikt via some Protocol?

Ja. Dit is precies waarvoor (voornamelijk) opaque type nodig is:

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

Typische fouten en anti-patronen

  • Verwarring tussen some Protocol en Protocol — verschillende gevallen en beperkingen
  • Overtreding van de regel van homogeniteit van het geretourneerde type in alle vertakkingen
  • Toepassen van some waar protocol of typealias eenvoudiger zou zijn

Voorbeeld uit het leven

Negatief geval

De functie retourneert protocol zonder opaque, wat het gebruik van methoden met associatedtype niet toestaat, complexe type erasure vereist, waardoor de code niet compileert of niet optimaal werkt.

Voordelen:

  • Flexibiliteit in abstracties zoals AnySequence

Nadelen:

  • Verlies van type safety, lage prestatie
  • Werkt niet met geassocieerde types

Positief geval

ViewBuilder in SwiftUI gebruikt some View, verbergt de details, verbetert type veiligheid, verhoogt compilatiesnelheid en runtime.

Voordelen:

  • Leesbare API, type safety, geen dynamic dispatch
  • Eenvoudige ondersteuning

Nadelen:

  • Geen verschillende types kunnen retourneren in één functie