Moderne Programmierung mit Swift, Teil 3
Zum Abschluss der Swift-Reihe sollen Operator Methods, Dateien und Interfaces Thema sein. AuĂźerdem geht es um das Zusammenspiel von Swift und Objective-C.
- Thomas Sillmann
In den bisherigen beiden Teilen zur modernen Programmierung mit Swift wurden bereits einige grundlegende Konzepte wie Initialisierung, Vererbung, Speicherverwaltung und Fehlerbehandlung betrachtet. Der abschließende Beitrag knüpft daran an und stellt zunächst mit den Operator Methods eine umfangreiche Möglichkeit vor, eigene Typen um Funktionen zu erweitern. Anschließend werden noch Dateien und Interfaces in Swift mitsamt der zugehörigen Access Control sowie das Zusammenspiel von Swift- und Objective-C-Code in einem Projekt betrachtet.
Swift verfügt über eine Vielzahl an Operatoren, um beispielsweise Berechnungen, Zuweisungen oder Vergleiche durchzuführen. Die sogenannten Operator Methods ermöglichen es, Methoden zu erstellen, die ein bestimmter Operator auslöst. Derartige Methoden sind nur für Strukturen und Klassen verfügbar.
Intern bildet Swift die Operator Methods als Typmethoden ab, was bedeutet, dass sie mit dem SchlĂĽsselwort static zu deklarieren sind. Als Methodenname kommt der gewĂĽnschte Operator zum Einsatz. Swift unterscheidet im Kontext der Operator Methods vier Arten von Operatoren :
- Binary Operator
- Compound Assignment Operator
- Prefix/Postfix Operator
- Equivalence Operator
Im Folgenden werden sie erläutert und die jeweiligen Einsatzzwecke vorgestellt.
Binary Operator
Entwickler nutzen den Binary Operator im Zusammenspiel mit zwei Instanzen eines bestimmten Typs. Beispielsweise dient der Additions-Operator + bei zwei Instanzen vom Typ Int dazu, sie miteinander zu addieren und das Ergebnis zurĂĽckzuliefern.
Wie sich eine eigene Operator Method auf Basis eines solchen Binary Operator erstellen lässt, zeigt das folgende Listing. Darin wird eine Structure Rectangle deklariert, die über die beiden Properties height und width verfügt. Der Plus-Operator soll es nun ermöglichen, zwei Instanzen dieses Typs – sprich deren jeweilige Höhe und Breite – miteinander zu addieren. Dazu ist eine passende Operator Method zu erstellen, deren Name der gewünschte Operator ist (in dem Fall also +) und die die zwei Parameter vom zugrundeliegenden Typ Rectangle entgegennimmt. Bei Letzterem handelt es sich zur Laufzeit um jene Instanzen, deren Flächen mittels Plus-Operator miteinander zu addieren sind. Als Ergebnis liefert die Methode eine neue Rectangle-Instanz mit der kalkulierten Fläche.
struct Rectangle {
var width: Int
var height: Int
static func + (firstValue: Rectangle, secondValue: Rectangle) -> Rectangle {
let width = firstValue.width + secondValue.width
let height = firstValue.height + secondValue.height
return Rectangle(width: width, height: height)
}
}
Der folgende Quelltextauszug zeigt die praktische Anwendung der erstellten Operator Method. In ihm wurden zwei Instanzen vom Typ Rectangle erstellt und anschlieĂźend durch den Plus-Operator miteinander addiert. Das Ergebnis wird einer neuen Konstante zugewiesen und anschlieĂźend in der Konsole ausgegeben.
let firstRectangle = Rectangle(width: 19, height: 99)
let secondRectanlge = Rectangle(width: 28, height: 88)
let thirdRectangle = firstRectangle + secondRectanlge
print("Breite: \(thirdRectangle.width)")
print("Höhe: \(thirdRectangle.height)")
// Breite: 47
// Höhe: 187
Derart lassen sich beliebige weitere Binary Operators in Form von Operator Methods umsetzen.
Compound Assignment Operator
Compound-Assignment-Operatoren sind eine Mischung aus Berechnungs- und Zuweisungsoperator. Beim Operator +=, der beispielsweise bei Instanzen vom Typ Int dazu dient, den Wert der Variablen links vom Operator um den Wert rechts davon zu erhöhen, handelt es sich um einen solchen Compound Assignment Operator.
Diese lassen sich ähnlich wie die zuvor gezeigten Binary Operators in eigenen Typen implementieren. Dazu erstellt man erneut eine Methode mit dem Namen des gewünschten Operators, die zwei Parameter entgegennimmt. Beim ersten handelt es sich beim Aufruf um jenen, der links vom Operator steht, beim zweiten um den rechts davon. Da ein Compound Assignment Operator den Wert des ersten Parameters verändert, ist es wichtig, ihn mit dem Schlüsselwort inout zu kennzeichnen. Einen Rückgabewert besitzen Operator Methods auf Basis eines Compound Assignment Operator nicht.
Der nächste Codeauszug bedient sich erneut des Beispiels der Rectangle-Structure und implementiert den Compound Assignment Operator +=, der jeweils die Breite und Höhe des zweiten Parameters mit der Breite und Höhe des ersten Parameters addieren soll.
struct Rectangle {
var width: Int
var height: Int
static func += (firstValue: inout Rectangle, secondValue: Rectangle) {
firstValue.width += secondValue.width
firstValue.height += secondValue.height
}
}
Genau wie bei dem eingangs genannten Integer-Beispiel lassen sich nun auchRectangle-Instanzen durch den Compound Assignment Operator verändern, wie das folgende Codebeispiel zeigt. Dort verändert die Operator Method die Variable firstRectangle entsprechend.
var firstRectangle = Rectangle(width: 19, height: 99)
let secondRectanlge = Rectangle(width: 28, height: 88)
firstRectangle += secondRectanlge
print("Breite: \(firstRectangle.width)")
print("Höhe: \(firstRectangle.height)")
// Breite: 47
// Höhe: 187
Prefix/Postfix Operator
Die sogenannten Prefix- und Postfix-Operatoren werden direkt auf eine Instanz eines Typs angewendet und dabei entweder vorangestellt (Prefix) oder am Ende aufgefĂĽhrt (Postfix). Ein Beispiel hierfĂĽr ist der Prefix-Operator ! im Zusammenspiel mit Instanzen vom Typ Bool, um deren Wert zu negieren. Ein anderes Beispiel ist der Postfix-Operator ?, der in Swift dem Deklarieren von Optionals dient.
Möchte man eine eigene Operator Method auf Grundlage eines solchen Operators erstellen, ist es wichtig, beim Deklarieren genau anzugeben, ob der Operator als Prefix- oder Postfix-Operator dienen soll. Dazu kommen die zugehörigen Schlüsselwörter prefix und postfix zum Einsatz, mit der die entsprechende Operator Method zu deklarieren ist. Als Parameter für die Methode kommt eine Instanz des zugrundeliegenden Typs zum Einsatz, auf die der Operator angewendet wird, und das Programm gibt eine neue Instanz mit dem Ergebnis der Operation zurück.
Im folgenden Beispiel taucht die Rectangle-Structure erneut auf. Sie ist um je einen Prefix- (+) und einen Postfix-Operator (--) ergänzt. Der Prefix-Operator + erhöht die Breite und Höhe der übergebenen Rectangle-Instanz jeweils um den Wert 10, während der Aufruf des Postfix-Operators -- beide Werte um 20 verringert.
struct Rectangle {
var width: Int
var height: Int
static prefix func + (rectangle: Rectangle) -> Rectangle {
let width = rectangle.width + 10
let height = rectangle.height + 10
return Rectangle(width: width, height: height)
}
static postfix func -- (rectangle: Rectangle) -> Rectangle {
let width = rectangle.width - 20
let height = rectangle.height - 20
return Rectangle(width: width, height: height)
}
}
Das nachfolgende Beispiel nutzt beide Operatoren, um jeweils eine Instanz der Structure Rectangle entsprechend zu verändern. Zu beachten ist die Position des Operators, sobald er auf eine Instanz angewendet wird. Da + ein Prefix-Operator ist, ist er einer Instanz voranzustellen, um die zugrundeliegende Operator Method aufzurufen, während der Postfix-Operator -- am Ende aufgeführt sein muss.
var firstRectangle = Rectangle(width: 19, height: 99)
firstRectangle = +firstRectangle
print("firstRectangle.width = \(firstRectangle.width)")
print("firstRectangle.height = \(firstRectangle.height)")
var secondRectangle = Rectangle(width: 50, height: 30)
secondRectangle = secondRectangle--
print("secondRectangle.width = \(secondRectangle.width)")
print("secondRectangle.height = \(secondRectangle.height)")
// firstRectangle.width = 29
// firstRectangle.height = 109
// secondRectangle.width = 30
// secondRectangle.height = 10