Advertisement
  1. Code
  2. Mobile Development
  3. iOS Development

Swift from Scratch: Vererbung und Protokolle

Scroll to top
Read Time: 12 min
This post is part of a series called Swift From Scratch.
Swift From Scratch: An Introduction to Classes and Structures
Swift From Scratch: Delegation and Properties

() translation by (you can also view the original English article)

Wenn Sie die vorherigen Artikel dieser Serie gelesen haben, sollten Sie die Grundlagen der Swift-Programmiersprache inzwischen gut verstehen. Wir haben über Variablen, Konstanten und Funktionen gesprochen, und im vorherigen Artikel haben wir die Grundlagen der objektorientierten Programmierung in Swift behandelt.

Während Spielplätze ein großartiges Werkzeug sind, um mit Swift zu spielen und die Sprache zu lernen, ist es Zeit, weiter zu machen und unser erstes Swift-Projekt in Xcode zu erstellen. In diesem Artikel werden wir die Grundlagen einer einfachen Aufgabenanwendung mit Xcode und Swift erstellen. Nebenbei lernen wir mehr über objektorientierte Programmierung und schauen uns auch die Integration zwischen Swift und Objective-C genauer an.

Voraussetzungen

Wenn Sie mir folgen möchten, stellen Sie sicher, dass Xcode 6.3 oder höher auf Ihrem Computer installiert ist. Zum Zeitpunkt der Erstellung dieses Artikels befindet sich Xcode 6.3 in der Betaversion und ist im Apple iOS Dev Center für registrierte iOS-Entwickler erhältlich.

Der Grund dafür, Xcode 6.3 oder höher zu verlangen, besteht darin, Swift 1.2 nutzen zu können, das Apple vor einigen Tagen eingeführt hat. Swift 1.2 führt eine Reihe von großartigen Ergänzungen ein, die wir im Rest dieser Serie nutzen werden.

1. Projekteinrichtung

Schritt 1: Wählen Sie eine Vorlage

Starten Sie Xcode 6.3 oder höher und wählen Sie Neu > Projekt ... im Menü Datei. Wählen Sie aus der Liste der iOS-Anwendungsvorlagen die Vorlage Einzelansichtsanwendung und klicken Sie auf Weiter.

Schritt 2: Konfigurieren Sie das Projekt

Benennen Sie das Projekt ToDo und legen Sie Sprache auf Swift fest. Stellen Sie sicher, dass Geräte auf iPhone eingestellt ist und das Kontrollkästchen Core-Daten verwenden deaktiviert ist. Klicke weiter um fortzufahren.

Sagen Sie Xcode, wo Sie Ihr Projekt speichern möchten, und klicken Sie rechts unten auf Erstellen, um Ihr erstes Swift-Projekt zu erstellen.

2. Projekt Anatomie

Bevor wir unsere Reise nach Swift fortsetzen, nehmen wir uns einen Moment Zeit, um zu sehen, was Xcode für uns geschaffen hat. Wenn Sie mit der Entwicklung von Xcode und iOS noch nicht vertraut sind, wird Ihnen das meiste neu sein. Durch die Arbeit mit einem Swift-Projekt erhalten Sie jedoch ein besseres Gefühl dafür, wie Klassen und Strukturen in Swift aussehen und sich verhalten.

Die Projektvorlage unterscheidet sich nicht wesentlich von einem Projekt, das mit Objective-C als Programmiersprache erstellt wurde. Die wichtigsten Unterschiede beziehen sich auf die Klassen AppDelegate und ViewController.

Wenn Sie in der Vergangenheit mit Objective-C gearbeitet haben, werden Sie feststellen, dass die Projektvorlage weniger Dateien enthält. In unserem Projekt befinden sich keine Header- (.h) oder Implementierungsdateien (.m). In Swift haben Klassen keine separate Header-Datei, in der die Schnittstelle deklariert ist. Stattdessen wird eine Klasse deklariert und in einer einzigen .swift-Datei implementiert.

Unser Projekt enthält derzeit zwei Swift-Dateien, eine für die AppDelegate-Klasse, AppDelegate.swift, und eine weitere für die ViewController-Klasse, ViewController.swift. Das Projekt enthält außerdem ein Storyboard, ein Main.Storyboard und eine XIB-Datei für den Startbildschirm LaunchScreen.xib. Wir werden ein wenig später in diesem Artikel mit dem Storyboard arbeiten. Es enthält derzeit nur die Szene für die ViewController-Klasse.

Es gibt eine Reihe anderer Dateien und Ordner, die im Projekt enthalten sind, aber wir werden diese für jetzt ignorieren. Sie spielen keine wichtige Rolle im Rahmen dieses Artikels.

3. Vererbung

Das erste, was wir in diesem Artikel behandeln, ist die Vererbung, ein gängiges Paradigma der objektorientierten Programmierung. In Swift können nur Klassen von einer anderen Klasse erben. Mit anderen Worten, Strukturen und Aufzählungen unterstützen keine Vererbung. Dies ist einer der Hauptunterschiede zwischen Klassen und Strukturen.

Öffnen Sie ViewController.swift, um die Vererbung in Aktion zu sehen. Die Benutzeroberfläche und die Implementierung der ViewController-Klasse ist ziemlich einfach, was es uns leichter macht, uns auf das Wesentliche zu konzentrieren.

UIKit

An der Spitze von ViewController.swift sollten Sie eine Import-Anweisung für das UIKit-Framework sehen. Denken Sie daran, dass das UIKit-Framework die Infrastruktur zum Erstellen einer funktionalen iOS-Anwendung bereitstellt. Die Importanweisung oben stellt uns diese Infrastruktur in ViewController.swift zur Verfügung.

1
import UIKit

Oberklasse

Unterhalb der import-Anweisung definieren wir eine neue Klasse namens ViewController. Der Doppelpunkt, nach dem der Klassenname nicht übersetzt wird, ist vom Typ, wie wir zuvor in dieser Serie gesehen haben. Stattdessen ist die Klasse nach dem Doppelpunkt die Oberklasse der ViewController-Klasse. Mit anderen Worten, das folgende Snippet könnte gelesen werden, wenn wir eine Klasse namens ViewController definieren, die von UIViewController erbt.

1
class ViewController: UIViewController {
2
3
}

Dies erklärt auch das Vorhandensein der Import-Anweisung oben in ViewController.swift, da die UIViewController-Klasse im UIKit-Framework definiert ist.

Überschreibungen

Die ViewController-Klasse enthält derzeit zwei Methoden. Beachten Sie jedoch, dass jeder Methode das Schlüsselwort override vorangestellt ist. Dies zeigt an, dass die Methoden in der Superklasse der Klasse - oder höher in der Vererbungsstruktur - definiert und von der ViewController-Klasse überschrieben werden.

1
class ViewController: UIViewController {
2
3
    override func viewDidLoad() {
4
        super.viewDidLoad()
5
    }
6
7
    override func didReceiveMemoryWarning() {
8
        super.didReceiveMemoryWarning()
9
    }
10
}

Das override konstrukt existiert nicht in Objective-C. In Objective-C implementieren Sie eine überschriebene Methode in einer Unterklasse, ohne explizit anzugeben, dass sie eine Methode oberhalb der Vererbungsstruktur überschreibt. Die Objective-C-Laufzeit kümmert sich um den Rest.

Das gleiche gilt für Swift, aber die Override-Schlüsselwörter fügen dem Override der Methode Sicherheit hinzu. Da wir der Methode viewDidLoad das Schlüsselwort override vorangestellt haben, erwartet Swift diese Methode in der Oberklasse der Klasse oder höher im Vererbungsbaum. Einfach gesagt, wenn Sie eine Methode überschreiben, die nicht in der Vererbungsstruktur existiert, wird Swift einen Fehler auslösen. Sie können dies testen, indem Sie die Methode viewDidLoad falsch schreiben, wie unten gezeigt.

4. Benutzeroberfläche

Outlets deklarieren

Fügen wir dem View-Controller eine Tabellenansicht hinzu, um eine Liste von Aufgaben anzuzeigen. Bevor wir das tun, müssen wir eine Steckdose für die Tabellenansicht erstellen. Eine Steckdose ist nichts anderes als eine Eigenschaft, die im Interface Builder sichtbar ist und eingestellt werden kann. Um eine Steckdose in der ViewController-Klasse zu deklarieren, setzen wir der Eigenschaft, einer Variablen, das @IBOutlet-Attribut als Präfix voran.

1
class ViewController: UIViewController {
2
    @IBOutlet var tableView: UITableView!
3
    
4
    override func viewDidLoad() {
5
        super.viewDidLoad()
6
    }
7
8
    override func didReceiveMemoryWarning() {
9
        super.didReceiveMemoryWarning()
10
    }
11
}

Beachten Sie, dass der Ausgang implizit optional ausgepackt ist. Ein Was? Lassen Sie mich zu Beginn sagen, dass eine Steckdose immer ein optionaler Typ sein muss. Der Grund ist einfach. Jede Eigenschaft der ViewController-Klasse muss nach der Initialisierung einen Wert haben. Eine Steckdose ist jedoch erst zur Laufzeit mit der Benutzeroberfläche verbunden, nachdem die ViewController-Instanz initialisiert wurde, daher der optionale Typ.

Warte eine Minute. Der TableView-Ausgang wird als implizit nicht ausgepackt, optional und nicht als optional deklariert. Kein Problem. Wir können den TableView-Ausgang als optional deklarieren, indem wir das Ausrufezeichen im obigen Snippet durch ein Fragezeichen ersetzen. Das würde gut kompilieren. Dies würde jedoch auch bedeuten, dass wir die Eigenschaft jedes Mal explizit entfernen müssen, wenn wir auf den im optionalen Wert gespeicherten Wert zugreifen möchten. Dies wird schnell umständlich und ausführlich.

Stattdessen deklarieren wir den outlet TableView als implizit unwrapped optional, was bedeutet, dass wir das optionale nicht explizit auspacken müssen, wenn wir auf seinen Wert zugreifen müssen. Kurz gesagt, ein implizit entpacktes optionales Element ist optional, aber wir können auf den im optionalen Element gespeicherten Wert wie eine reguläre Variable zugreifen. Es ist wichtig zu beachten, dass Ihre Anwendung abstürzt, wenn Sie versuchen, auf ihren Wert zuzugreifen, wenn kein Wert festgelegt wurde. Das ist die Frage. Wenn die Steckdose richtig angeschlossen ist, können wir sicherstellen, dass die Steckdose richtig eingestellt ist.

Ausgänge verbinden

Nachdem der Ausgang deklariert wurde, ist es an der Zeit, ihn im Interface Builder zu verbinden. Öffnen Sie Main.storyboard, und wählen Sie den Ansichtscontroller aus. Wählen Sie im Menü Editor die Option Einbetten in > Navigation Controller. Dies setzt den View-Controller als Root-View-Controller eines Navigations-Controllers. Mach dir jetzt keine Sorgen darüber.

Ziehen Sie eine UITableView-Instanz aus der Objektbibliothek in die Ansicht des Ansichtscontrollers, und fügen Sie die erforderlichen Layouteinschränkungen hinzu. Wenn die Tabellenansicht ausgewählt ist, öffnen Sie den Inspektor Verbindungen und legen Sie die DataSource- und Delegate-Ausgänge der Tabellenansicht auf den View-Controller fest.

Wenn der Connections Inspector noch geöffnet ist, wählen Sie den View-Controller aus, und verbinden Sie den TableView-Ausgang mit der gerade hinzugefügten Tabellenansicht. Dies verbindet den TableView-Ausgang der ViewController-Klasse mit der Tabellenansicht.

5. Protokolle

Bevor wir die Anwendung erstellen und ausführen können, müssen wir die Protokolle UITableViewDataSource und UITableViewDelegate in der ViewController-Klasse implementieren. Dies beinhaltet mehrere Dinge.

Schritt 1: Übereinstimmung mit Protokollen

Wir müssen dem Compiler mitteilen, dass die ViewController-Klasse den UITableViewDataSource- und UITableViewDelegate-Protokollen entspricht. Die Syntax sieht ähnlich aus wie in Objective-C.

1
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
2
    ...
3
}

Die Protokolle, denen die Klasse entspricht, sind nach der Oberklasse UIViewController im obigen Beispiel aufgelistet. Wenn eine Klasse keine Superklasse hat, was in Swift nicht ungewöhnlich ist, werden die Protokolle unmittelbar nach dem Klassennamen und dem Doppelpunkt aufgelistet.

Schritt 2: Implementieren des UITableViewDataSource-Protokolls

Da das UITableViewDelegate-Protokoll keine erforderlichen Methoden definiert, implementieren wir das UITableViewDataSource-Protokoll nur für den Augenblick. Bevor wir das tun, erstellen wir eine Variableneigenschaft, um die Aufgaben zu speichern, die wir in der Tabellenansicht auflisten werden.

1
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
2
    @IBOutlet var tableView: UITableView!
3
    
4
    var items: [String] = []
5
    
6
    ...
7
}

Wir deklarieren eine Variableneigen items des Typs [String] und setzen ein leeres Array [] als Anfangswert. Dies sollte jetzt bekannt vorkommen. Als Nächstes implementieren wir die zwei erforderlichen Methoden des UITableViewDataSource-Protokolls.

Die erste erforderliche Methode, numberOfRowsInSection(_:), ist einfach. Wir geben einfach die Anzahl der Elemente zurück, die in der Eigenschaft items gespeichert sind.

1
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
2
    return self.items.count
3
}

Die zweite erforderliche Methode, cellForRowAtIndexPath(_:), benötigt ein wenig mehr Erläuterungen. Wenn wir die Subscript-Syntax verwenden, fragen wir nach dem richtigen Element aus dem Array von Aufgabenelementen.

1
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
2
    // Fetch Item

3
    let item = self.items[indexPath.row]
4
    
5
    // Dequeue Table View Cell

6
    let tableViewCell = tableView.dequeueReusableCellWithIdentifier("TableViewCell", forIndexPath: indexPath) as! UITableViewCell
7
    
8
    // Configure Table View Cell

9
    tableViewCell.textLabel?.text = item
10
    
11
    return tableViewCell
12
}

Wir fragen dann in der Tabellenansicht nach einer Zelle mit dem Bezeichner "TableViewCell" und übergeben den Indexpfad für die aktuelle Zeile. Beachten Sie, dass wir die Zelle in einer Konstanten namens  tableViewCell speichern. Sie müssen tableViewCell nicht als Variable deklarieren.

Ein weiteres wichtiges Detail ist, dass wir den Rückgabewert von dequeueReusableCellWithIdentifier(_:forIndexPath:) zu UITableViewCell zurücknehmen, da es ein Objekt vom Typ AnyObject zurückgibt, das id in Objective-C entspricht. Um AnyObject zu UITableViewCell downcast, verwenden wir das Schlüsselwort as.

Wir könnten das as verwenden? Variante, die auf einen optionalen Typ reduziert wird, aber da wir sicher sein können, dass dequeueReusableCellWithIdentifier(_:forIndexPath:) immer eine korrekt initialisierte Instanz zurückgibt, können wir das as! Schlüsselwort, das Ergebnis des Methodenaufrufs wird implizit ausgepackt.

In der nächsten Codezeile konfigurieren wir die Tabellenansichtszelle und setzen den Text des Textlabels mit dem Wert des item. Beachten Sie, dass in Swift die Eigenschaft textLabel von UITableViewCell als optionaler Typ deklariert ist, daher das Fragezeichen. Diese Codezeile könnte gelesen werden, wenn die text -Eigenschaft des Textlabels auf item gesetzt wird, wenn textLabel ungleich nil ist. Mit anderen Worten, die text -Eigenschaft des Textlabels wird nur gesetzt, wenn textLabel nicht nil ist. Dies ist ein sehr praktisches Sicherheitskonstrukt in Swift, das als optionale Verkettung bekannt ist.

Schritt 3: Wiederverwendung der Zellen

Es gibt zwei Dinge, die wir vor dem Erstellen der Anwendung klären müssen. Zuerst müssen wir der Tabellenansicht mitteilen, dass sie die UITableViewCell-Klasse verwenden muss, um neue Tabellenansichtszellen zu erstellen. Dazu rufen wir registerClass(_:forCellReuseIdentifier:) auf, übergeben die UITableViewCell-Klasse und die bereits verwendete Wiederverwendungs-ID "TableViewCell". Aktualisieren Sie die viewDidLoad-Methode wie unten gezeigt.

1
override func viewDidLoad() {
2
    super.viewDidLoad()
3
    
4
    // Register Class for Cell Reuse

5
    self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "TableViewCell")
6
}

Schritt 4: Hinzufügen von Elementen

Derzeit sind keine Elemente in der Tabellenansicht verfügbar. Dies lässt sich leicht lösen, indem Sie die Eigenschaft items mit einigen Aufgaben füllen. Es gibt mehrere Möglichkeiten, dies zu erreichen. Ich habe gewählt, um die Eigenschaft items in der Methode viewDidLoad zu füllen, wie unten gezeigt.

1
override func viewDidLoad() {
2
    super.viewDidLoad()
3
    
4
    // Populate Items

5
    self.items = ["Buy Milk", "Finish Tutorial", "Play Minecraft"]
6
    
7
    // Register Class for Cell Reuse

8
    self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "TableViewCell")
9
}

6. Erstellen und Ausführen

Es ist Zeit, unsere Anwendung für eine Drehung zu nehmen. Wählen Sie Ausführen im Xcode-Produktmenü oder drücken Sie Befehl-R. Wenn Sie gefolgt sind und Swift 1.2 verwenden, sollten Sie das folgende Ergebnis erhalten.

Beachten Sie, dass ich oben in der Ansicht in der Navigationsleiste den Titel To Do hinzugefügt habe. Sie können dasselbe tun, indem Sie die title-Eigenschaft der ViewController-Instanz in der viewDidLoad-Methode festlegen.

1
override func viewDidLoad() {
2
    super.viewDidLoad()
3
    
4
    // Set Title

5
    self.title = "To Do"
6
    
7
    // Populate Items

8
    self.items = ["Buy Milk", "Finish Tutorial", "Play Minecraft"]
9
    
10
    // Register Class for Cell Reuse

11
    self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "TableViewCell")
12
}

Erfahren Sie mehr in unserem Swift Programming Kurs

Wenn Sie daran interessiert sind, Ihre Swift-Ausbildung auf die nächste Stufe zu bringen, können Sie sich unseren vollständigen Kurs zur Entwicklung von Swift ansehen.

Fazit

Obwohl wir eine einfache Anwendung erstellt haben, haben Sie einige neue Dinge gelernt. Wir haben Vererbungs- und Überschreibungsmethoden untersucht. Wir haben auch Protokolle behandelt und wie das UITableViewDataSource-Protokoll in der ViewController-Klasse übernommen wird. Das Wichtigste, was Sie jedoch gelernt haben, ist die Interaktion mit Objective-C-APIs.

Es ist wichtig zu verstehen, dass die APIs des iOS SDK in Objective-C geschrieben sind. Swift wurde entwickelt, um mit diesen APIs kompatibel zu sein. Aufgrund früherer Fehler erkannte Apple, dass Swift in der Lage war, sich in das iOS SDK einzuklinken, ohne jedes einzelne API in Swift neu schreiben zu müssen.

Die Kombination von Objective-C und Swift ist möglich, aber es gibt einige Vorbehalte, die wir im weiteren Verlauf genauer untersuchen werden. Wegen Swifts unablässigem Fokus auf Sicherheit müssen wir von Zeit zu Zeit einige Hürden nehmen. Keine dieser Hürden ist jedoch zu groß, um das zu tun, wie wir im nächsten Artikel erfahren werden, in dem wir weiter an unserer To-Do-Anwendung arbeiten.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.