ProgrammierungMid/Senior iOS-Entwickler

Was sind Subscripts in Swift und wie kann man sie überschreiben oder erweitern? Geben Sie ein Beispiel für eine fortgeschrittene Nutzung.

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

Antwort.

Subscripts in Swift bieten eine bequeme Syntax zum Zugriff auf Elemente von Sammlungen, Containern oder benutzerdefinierten Typen mithilfe von Indizes, ähnlich wie bei Arrays und Dictionaries. Sie können in eigenen Klassen, Strukturen und Aufzählungen deklariert und überschrieben werden.

Geschichte der Frage

Subscripts wurden in Swift eingeführt, um einen einheitlichen, indizierten Zugriff auf Objekte zu ermöglichen, beginnend mit Sammlungen und dann auf beliebige benutzerdefinierte Typen ausgeweitet. Die Hauptaufgabe besteht darin, die Ausdruckskraft und Lesbarkeit zu erhöhen und Zugriffsmethoden auf Daten in eine "natürliche" Syntax zu verwandeln, die an die Arbeit mit Arrays erinnert.

Problem

In anderen Programmiersprachen (z.B. Java) erfolgt der Zugriff auf ein Element einer Struktur über Methoden wie get/set, was den Code umständlich macht. Das Streben nach besserer Lesbarkeit und erleichtertem Zugang zu Daten führte zur Einführung von Subscripts. In Swift ist besonderen Wert auf sicheren Zugriff, Getter und Setter sowie auf mögliche Fehler und zurückgegebene optionale Werte zu legen.

Lösung

Ein Subscript kann in jeder Klasse, Struktur oder Aufzählung mithilfe des Schlüsselworts "subscript" deklariert werden. Es unterstützt außerdem mehrere Überladungen je nach Parametern und Rückgabetypen.

Beispiel für ein benutzerdefiniertes Subscript:

struct Matrix { let rows: Int, columns: Int private var grid: [Double] init(rows: Int, columns: Int) { self.rows = rows self.columns = columns grid = Array(repeating: 0.0, count: rows * columns) } subscript(row: Int, column: Int) -> Double { get { precondition(row >= 0 && row < rows) precondition(column >= 0 && column < columns) return grid[(row * columns) + column] } set { precondition(row >= 0 && row < rows) precondition(column >= 0 && column < columns) grid[(row * columns) + column] = newValue } } } var matrix = Matrix(rows: 2, columns: 2) matrix[1, 1] = 3.14 print(matrix[1, 1]) // 3.14

Hauptmerkmale:

  • Es können mehrere Subscripts mit unterschiedlichen Typen und Anzahlen von Parametern definiert werden
  • Das Subscript kann nur get oder sowohl get/set sein
  • Man kann Subscripts mit verschiedenen Typen von Indizes verwenden, sogar mit Bereichen und Strings

Trickfragen.

Kann man ein Subscript nur mit einem Getter, ohne Setter, deklarieren?

Ja. Wenn das Subscript nur für das Lesen benötigt wird, reicht es aus, nur den Getter zu implementieren.

struct ReadOnlyArray { private let items = [1, 2, 3] subscript(index: Int) -> Int { get { return items[index] } } }

Darf man in einem Typ mehrere Subscripts mit unterschiedlicher Signatur deklarieren?

Ja, Subscripts können nach Anzahl und Typ der Parameter überladen werden.

struct Collection { subscript(index: Int) -> String { ... } subscript(key: String) -> Int? { ... } }

Kann ein Subscript in einem Protokoll deklariert und in einer Struktur/Klasse implementiert werden?

Ja, Protokolle können die Implementierung eines Subscripts verlangen, und spezifische Typen sind verpflichtet, diese zu implementieren.

protocol MySubscriptable { subscript(index: Int) -> String { get set } } struct SubData: MySubscriptable { private var items = ["a", "b"] subscript(index: Int) -> String { get { return items[index] } set { items[index] = newValue } } }

Typische Fehler und Anti-Patterns

  • Unsicherer Zugriff ohne Grenzkontrollen (precondition, bounds check)
  • Datentypfehler für Subscript-Parameter
  • Übermäßige Verwendung von Subscripts ohne Notwendigkeit, wo besser Methoden verwendet werden sollten

Beispiele aus dem Leben

Negativer Fall

Ein Entwickler implementierte ein Subscript ohne Grenzkontrolle. Infolgedessen stürzte die Anwendung mit einem Laufzeitfehler ab, als auf einen nicht existierenden Index zugegriffen wurde.

Vorteile: Der Code wurde kompakter.

Nachteile: Die Anwendung begann aufgrund plötzlicher Fehler abzustürzen.

Positiver Fall

Implementierung eines Subscripts mit Precondition und der Möglichkeit, optionale Werte zurückzugeben oder Fehler auszulösen.

Vorteile: Der Code wurde sicherer für den Benutzer, Fehler konnten behandelt werden.

Nachteile: Es muss zusätzliche Fehlerbehandlungslogik implementiert und das Verhalten für ungültige Indizes berücksichtigt werden.