iOS-Apps mit Swift 2

Das umfassende Praxis-Handbuch

Holger Hinzberg

Teil II: iOS-Apps

In diesem Teil:

Teil I: Grundlagen der Sprache Swift

In diesem Teil:

Referenzkarte

Variablen und Konstanten

// Variablen und Konstanten
var variableValue = 3.1415
variableValue = 3.0
let constValue = 42
// Neue Zuweisung nicht möglich
// constValue = 50

Fallunterscheidungen

var salary = 10000
if salary > 15000
{
    print("Zu viel")
}
else if salary < 10000
{
    print("Zu wenig")
}
else
{
    print("Ok")
}
 
var index = 4
switch index
{
    case 1:
        print("Index ist 1")
    case 2:
        print("Index ist 2")
    case 3...5:
        print("Index liegt zwischen 3 und 5")
    case 6:
        print("Index ist 6")
        fallthrough
    default:
        print("Index liegt nicht zwischen 1 bis 5")
}

Schleifen

for var index = 0; index <= 5; index++
{
    print(index) // Ausgabe von 0 bis 5
}
 
for index in 0...5 // Closed Range
{
    print(index) // Ausgabe von 0 bis 5
}
 
for index in 0..<5 // Half-Open Range
{
    print(index) // Ausgabe von 0 bis 4
}
 
for index in (5...10).reverse()
{
    print(index) // Ausgabe von 10 bis 5
}
 
var access = 1
repeat
{
    print(access) // Ausgabe von 1 bis 9
    access++
}
while access < 10
                

Array

var cities:[String] = ["Rom","Paris","Berlin"]
cities.append("London")
 
for city in cities
{
    print(city) // Ausgabe aller Städtenamen
}
 
var count = cities.count // Anzahl der Elemente
                

Methoden/Funktionen

// Ohne Parameter und ohne Rückgabewert
func doSomething()
{
    print("Hello World!")
}
 
doSomething()
 
// Mit einem Double als Parameter und einem Double
// als Rückgabewert
func doSomething(value:Double) -> Double
{
    return value * 2.0
}
 
var twice = doSomething(4.5)
 
// Mit zwei benannten Parametern
// und einem Double als Rückgabewert
func doSomething(
  firstValue first:Double, secondValue second:Double) -> Double
{
   return first + second
}
 
var sum = doSomething(firstValue: 3.2, secondValue: 4.7)
                

Dictionary

var animals:[Int: String] = [11:"Hund", 22:"Katze", 33:"Maus"]
animals[22] = "Elefant" // Element ersetzen
animals[99] = "Huhn" // Element anfügen
print(animals[22]) // Ausgabe "Optional (Elefant)"
print(animals[99]) // Ausgabe "Optional (Huhn)"
animals[11] = nil // Element entfernen
                

Zeichenketten

var firstName = "Mike"
var lastName = "Müller"
// String-Interpolation
print("Mein Name ist \(firstName) \(lastName).")
 
// Zahlenwerte formatieren
var numeric = 3.34983632
var num = String(format:"%.2f", numeric) // Ausgabe 3.35
                

Klassen

class Person
{
    // Eigenschaften
    var firstName:String
    var lastName:String
    init()
    {
        // Eigenschaften initialisieren
        firstName = ""
        lastName = ""
    }
}
 
// Klasseninstanz erzeugen und 
// Eigenschaften zuweisen
var pers = Person()
pers.firstName = "Mike"
pers.lastName = "Müller"
                

Enumerationen

enum Color
{
    case Red
    case Green
    case Blue
}
var exterior:Color = Color.Green
                

Fehlerbehandlung mit try-catch

// Eigene Fehlertypen definieren
enum CalculationError : ErrorType
{
    case DivideByZero
    case OtherError
}
 
// Funktion kann einen Fehler zurückgeben
func divide(dividend:Int, divisor:Int) throws -> Int
{
    guard divisor > 0 else
    {
        throw CalculationError.DivideByZero
    }
    return dividend / divisor
}
 
// Funktionsaufruf und Fehlerbehandlung 
do
{
    var result = try divide(100, divisor: 0)
}
catch(CalculationError.DivideByZero)
{
    print("Es wurde versucht, durch null zu teilen")
}
catch
{
    print("Ein anderer Fehler ist aufgetreten")
}

Impressum

Bibliografische Information der Deutschen Nationalbibliothek

Die Deutsche Nationalbibliothek verzeichnet diese Publikation in der Deutschen Nationalbibliografie; detaillierte bibliografische Daten sind im Internet über <http://dnb.d-nb.de> abrufbar.

ISBN 978-3-95845-223-7

1. Auflage 2016

www.mitp.de

E-Mail: mitp-verlag@sigloch.de

Telefon: +49 7953 / 7189 - 079

Telefax: +49 7953 / 7189 - 082

© 2016 mitp Verlags GmbH & Co. KG

Dieses Werk, einschließlich aller seiner Teile, ist urheberrechtlich geschützt. Jede Verwertung außerhalb der engen Grenzen des Urheberrechtsgesetzes ist ohne Zustimmung des Verlages unzulässig und strafbar. Dies gilt insbesondere für Vervielfältigungen, Übersetzungen, Mikroverfilmungen und die Einspeicherung und Verarbeitung in elektronischen Systemen.

Die Wiedergabe von Gebrauchsnamen, Handelsnamen, Warenbezeichnungen usw. in diesem Werk berechtigt auch ohne besondere Kennzeichnung nicht zu der Annahme, dass solche Namen im Sinne der Warenzeichen- und Markenschutz-Gesetzgebung als frei zu betrachten wären und daher von jedermann benutzt werden dürften.

Lektorat: Sabine Schulz

Sprachkorrektorat: Petra Heubach-Erdmann

Coverbild: © Max Krasnov @ fotolia.de

electronic publication: III-satz, Husby, www.drei-satz.de

Dieses Ebook verwendet das ePub-Format und ist optimiert für die Nutzung mit dem iBooks-reader auf dem iPad von Apple. Bei der Verwendung anderer Reader kann es zu Darstellungsproblemen kommen.

Der Verlag räumt Ihnen mit dem Kauf des ebooks das Recht ein, die Inhalte im Rahmen des geltenden Urheberrechts zu nutzen. Dieses Werk, einschließlich aller seiner Teile, ist urheberrechtlich geschützt. Jede Verwertung außerhalb der engen Grenzen des Urheherrechtsgesetzes ist ohne Zustimmung des Verlages unzulässig und strafbar. Dies gilt insbesondere für Vervielfältigungen, Übersetzungen, Mikroverfilmungen und Einspeicherung und Verarbeitung in elektronischen Systemen.

Der Verlag schützt seine ebooks vor Missbrauch des Urheberrechts durch ein digitales Rechtemanagement. Bei Kauf im Webshop des Verlages werden die ebooks mit einem nicht sichtbaren digitalen Wasserzeichen individuell pro Nutzer signiert.

Bei Kauf in anderen ebook-Webshops erfolgt die Signatur durch die Shopbetreiber. Angaben zu diesem DRM finden Sie auf den Seiten der jeweiligen Anbieter.

Kapitel 33: Daten suchen und finden

In der Familie der Programmiersprachen, die von der Sprache C abstammen, hat Objective-C eine Außenseiterposition, denn die Sprache unterscheidet sich teilweise sehr von ihren Geschwistern. Swift hat einige der Eigenschaften übernommen und verfügt ebenfalls über eine spezielle Art von Datenzugriff, die in anderen Programmiersprachen nicht oder komplett anders umgesetzt werden. Falls Sie bisher ausschließlich mit anderen Sprachen gearbeitet haben, erwarten Sie in diesem Kapitel einige Überraschungen.

Auf den folgenden Seiten werden wir zunächst keine App entwickeln, trotzdem sollten Sie alle vorgestellten Beispiele programmieren und dabei mit den Anweisungen spielen und andere Parameter oder andere Werte ausprobieren. Zum Experimentieren gut geeignet ist die main.swift-Datei einer OS-X-Konsolenanwendung (Command Line Tool). Der Code dort wird beim Start der Anwendung automatisch ausgeführt. Zusätzliche Interaktionen, wie das Auswählen einer Schaltfläche, sind dann nicht notwendig.

33.1  Zugriff mit Key Value Coding

Sollen die Instanzvariablen eines Objekts manipuliert werden, geschieht das in der Regel über einen Zugriff auf die öffentlichen Eigenschaften der Klasse oder über Methoden. Beide Möglichkeiten unterstützen das Konzept der Kapselung​ und erlauben Veränderungen ausschließlich über definierte »Zugänge«. Soll eine Instanzvariable von außerhalb der Klasse aus nur gelesen werden können, lässt sich das ebenfalls mit geringem Aufwand konfigurieren. Swift unterscheidet sich dort nur wenig von anderen Programmiersprachen.

Eine Besonderheit ist das Key Value Coding​-(KVC-)Verfahren, bei dem der Zugriff auf die Eigenschaften über deren Namen als Zeichenkette geschieht. Das mag im ersten Moment seltsam erscheinen und unverständlich klingen – KVC schafft in der Entwicklung aber zusätzliche Möglichkeiten, die es erlauben, mit geschickter Programmierung viele Codezeilen einzusparen. Erinnern wir uns zunächst, wie wir bisher gearbeitet haben.

let truck = Truck()
 
// Zugriff mit Punktnotation
truck.make = "Megatrucker"
truck.color = "Schwarz"
truck.wheels = 4
 
print("Marke: \(truck.make)")
print("Farbe: \(truck.color)")
print("Anzahl der Räder: \(truck.make)")

Im Listing geschieht der lesende und schreibende Zugriff auf die Eigenschaften der Klasse Truck mit der Punktnotations-Syntax​. Für moderne Projekte ist das die leichteste Art der Programmierung. Die Entwicklungsumgebung unterstützt die Schreibweise und unterbreitet während der Eingabe Vorschläge.

Eine alternative Möglichkeit, der Zugriff über Key Value Coding​, verlangt eine andere Syntax. Dort kommen für einen Zugriff die Methoden setValue(_: forKey:) und valueForKey zum Einsatz. Der Name einer Eigenschaft wird über den Parameter Key und als Typ String übergeben.

let truck = Truck()
 
// Zugriff mit KVC
truck.setValue("Megatrucker", forKey: "make")
truck.setValue("Schwarz", forKey: "color")
truck.setValue(4, forKey: "wheels")
 
print("Marke: \(truck.valueForKey("make"))")
print("Farbe: \(truck.valueForKey("color"))")
print("Anzahl der Räder: \(truck.valueForKey("wheels"))")

Im Gegensatz zur Punktnotation funktioniert Key Value Coding in der aktuellen Swift-Version ausschließlich mit Klassen, die in ihrem Stammbaum von NSObject​ abgeleitet sind. Außerdem kann KVC mit Zahlendatentypen nur arbeiten, wenn sie keine Optionals sind. Der Rückgabewert von valueForKey ist allerdings immer ein Optional vom Typ AnyObject. Die verwendete Klasse Truck sieht so aus:

import Foundation
 
class Truck: NSObject
{
    var make:String?
    var color:String?
    var wheels:Int = 0
}

Die Frage, warum man auf diese Art programmieren sollte, lässt sich einfach beantworten: Tun Sie es nicht! KVC mit unveränderlichen Zeichenketten bringt keine Vorteile und trägt auch nicht zur besseren Lesbarkeit des Programmcodes bei. Interessant wird das Verfahren, sobald die Namen der Eigenschaften in Variablen oder Konstanten abgelegt werden.

let truck = Truck()
 
// Zugriff mit Punktnotation
let makeKey = "make"
let colorKey = "color"
let wheelsKey = "wheels"
 
// Zugriff mit KVC
truck.setValue("Megatrucker", forKey: makeKey)
truck.setValue("Schwarz", forKey: colorKey)
truck.setValue(4, forKey: wheelsKey)
 
print("Marke: \(truck.valueForKey(makeKey))")
print("Farbe: \(truck.valueForKey(colorKey))")
print("Anzahl der Räder: \(truck.valueForKey(wheelsKey))")

Mit Variablen, die unveränderlich im Code definiert sind, erreicht man ebenfalls keine Flexibilität im Programm, aber vielleicht erkennen Sie jetzt die Möglichkeiten. Der Variablenwert kann die Eingabe eines Anwenders oder der Parameter einer Methode sein, woraufhin dann eine andere Eigenschaft ausgegeben wird. Andere Einsatzmöglichkeiten ergeben sich, wenn mehrere Schlüssel in einem Array zusammengefasst werden. Mit einer Schleife ist es dann leicht, sämtliche Eigenschaften eines Objekts auszugeben. Das folgende Listing zeigt, wie das in einfacher Form funktioniert.

let keys = ["make", "color", "wheels"]
 
for key in keys
{
    print("Wert: \(key) für Key: \(truck.valueForKey(key)!)")
}

Leider kommt Key Value Coding nicht ohne Gefahren. Weil der Name der Eigenschaften über eine Zeichenkette definiert wird, ist eine Überprüfung durch den Compiler nicht mehr möglich. Erneut treffen wir auf String Dependencies​, die Abhängigkeit von Zeichenketten. Verwendet man Bezeichner, die keinem Eigenschaftennamen entsprechen, führt das unweigerlich zu einem Programmfehler. Probieren Sie die folgende Anweisung aus:

truck.setValue("Mike", forKey: "driver")

Die Klasse Truck verfügt über keine Eigenschaft mit dem Namen driver, was vom Compiler bei der Übersetzung des Programmcodes nicht bemerkt wird. Er kann die KVC-Schreibweise nicht analysieren. Erst zur Laufzeit macht sich das Problem bemerkbar und Xcode schreibt eine umfangreiche Fehlermeldung auf die Konsole. Für die Klasse Truck ist es nicht möglich, mit Key Value Coding auf eine Eigenschaft mit dem Namen driver zuzugreifen:

setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key driver.

33.2  Schlüsselpfade und Aggregatfunktionen

Viele Klassen verwenden für ihre Eigenschaften wiederum Klassen, und möchte man dann auf Eigenschaften zugreifen, bilden sich Schlüsselpfade​ (englisch: Key Path​), bei denen die Namen der einzelnen Eigenschaften zu einer langen Kette verbunden werden. Das können wir leicht ausprobieren. Erweitern Sie Ihr Projekt um die nachfolgende Klasse Engine und die Klasse Truck dann um eine Eigenschaft dieser Klasse.

import Foundation
 
class Engine: NSObject
{
    var fuel:String?
    var power:Int = 0
}
Die erweiterte Klasse Truck:
import Foundation
 
class Truck: NSObject
{
    var make:String?
    var color:String?
    var wheels:Int = 0
    var engine = Engine()
}

Sowohl beim schreibenden als auch beim lesenden Zugriff werden die verschiedenen Eigenschaften mit der Punktnotation aneinandergereiht.

let truck = Truck()
truck.engine  = Engine()
 
truck.engine.power = 125
truck.engine.fuel = "Diesel"
 
print("Leistung: \(truck.engine.power)")
print("Kraftstoff: \(truck.engine.fuel)")

Der Schlüsselpfad, also der Weg zur gewünschten Eigenschaft, ist für die Kraftstoffart truck.engine.fuel und für die Leistung truck.engine.power. Für vergleichbare Zugriffe mit KVC bietet das Framework die Methode valueForKeyPath an. Der Rückgabetyp ist auch dort wieder ein Optional AnyObject.

print("Leistung: \(truck.valueForKeyPath("engine.power"))")
print("Kraftstoff: \(truck.valueForKeyPath("engine.fuel"))")

Ist eine Eigenschaft eine Auflistung, zum Beispiel ein Array, schaffen die Schlüsselpfade zusätzliche Wege, Informationen von einem Objekt zu erhalten. Leicht ausprobieren können wir das, indem wir das Projekt um eine zusätzliche Swift-Klasse mit dem Namen Destination erweitern, in der die verschiedenen Ziele für unseren LKW abgelegt werden. Um das Beispiel einfach zu halten, verfügt die Klasse nur über die Eigenschaften distance für die Entfernung und destinationDescription für eine Bezeichnung. Den Namen description können wir für eine Eigenschaft nicht verwenden. Sie wurde bereits in der Elternklasse deklariert und hat andere Aufgaben.

import Foundation
 
class Destination: NSObject
{
    var distance:Int = 0
    var destinationDescription:String?
}

Weil ein LKW nicht nur ein einziges Ziel ansteuern kann, ist die neue Eigenschaft destinations in der Datei Truck.swift nicht vom Typ Destination, sondern ein Array, das mehrere Destination-Objekte aufnehmen kann.

import Foundation
 
class Truck: NSObject
{
    var make:String?
    var color:String?
    var wheels:Int = 0
    var engine = Engine()
    var route = [Destination]()
}

Jetzt ist es kein Problem mehr, einem Truck-Objekt ein oder mehrere Ziele zuzuweisen.

let truck = Truck()
 
var des = Destination()
des.destinationDescription = "Bahnhof"
des.distance = 100
truck.destinations.append(des)
 
des = Destination()
des.destinationDescription = "Hafen"
des.distance = 75
truck.destinations.append(des)
 
des = Destination()
des.destinationDescription = "Flugplatz"
des.distance = 245
truck.destinations.append(des)
 
des = Destination()
des.destinationDescription = "Hafen"
des.distance = 130
truck.destinations.append(des)

Sollen anschließend sämtliche Ziele ausgegeben werden, so ist destinations.destinationDescription der für valueForKeyPath benötigte Schlüsselpfad. Der Rückgabetyp dieser Methode ist wieder AnyObject und muss vor der Ausgabe in ein String-Array umgewandelt werden.

// Sämtliche Ziele ermitteln und ausgeben
var allDescriptions = truck.valueForKeyPath(
    "destinations.destinationDescription") as! [String]
 
for descrip in allDescriptions
{
    print("Ziel: \(descrip)")
}

Möchte man explizit die Anzahl der Ziele abfragen, kann dies über die Aggregatfunktion @count geschehen, die ebenfalls ein KVC-Aufruf ist. Ein direkter Zugriff auf die Eigenschaft count des Arrays ist hingegen nicht möglich.

// Die Anzahl der Ziele ausgeben
print(truck.valueForKeyPath("destinations.@count"))

Benötigt man die Summe aller Entfernungen, muss man die einzelnen Strecken nicht selbst addieren. Key Value Coding verfügt über die Funktion @sum, die die Summe für uns berechnet.

// Die Summe der einzelnen Entfernungen
print(truck.valueForKeyPath("destinations.@sum.distance"))

Die längste und die kürzeste Entfernung in der Auflistung lassen sich auch ohne große Mühe ermitteln, indem man die Funktionen @min und @max einsetzt.

// Die kürzeste und die längste Entfernung
print(truck.valueForKeyPath("destinations.@min.distance"))
print(truck.valueForKeyPath("destinations.@max.distance"))

Wird die durchschnittliche Entfernung benötigt, muss dieser Betrag ebenfalls nicht von uns berechnet werden. Die Aggregatfunktion​ @avg kann dies übernehmen.

// Die durchschnittliche Entfernung
print(truck.valueForKeyPath("destinations.@avg.distance"))

Eine andere nützliche Funktion ist @distinctUnionOfObjects, die eine echte oder unechte Teilmenge von eindeutigen und unterscheidbaren Objekten aus einer Auflistung liefert. Obwohl unser LKW mehrfach den Hafen anfährt, wird das Ziel durch die folgenden Befehle nur einmal ausgegeben.

// Liste der Ziele (eindeutig)
var distinctDescriptions = truck.valueForKeyPath(
"destinations.@distinctUnionOfObjects.destinationDescription")
  as! [String]
 
for descrip in distinctDescriptions
{
    print("Ziel: \(descrip)")
}

Die meisten Entwickler werden Key Value Coding vermutlich nur selten einsetzen, denn die Programmierung mit Eigenschaften und Punktnotation ist einfacher und überschaubarer. Die verschiedenen Aggregatfunktionen sollten Sie aber kennen. Mit ihnen lässt sich eine Menge an Programmcode einsparen. Swift übernimmt bereitwillig oft benötigte Berechnungen von Summen und durchschnittlichen Werten, um die wir uns sonst selbst kümmern müssten.

33.3  Listen filtern mit NSPredicate

Aus einer Menge von Daten eine Untermenge herauszufiltern​, die bestimmten Kriterien entspricht, ist in der Softwareentwicklung kein ungewöhnliches Anliegen und kann auf viele unterschiedliche Arten realisiert werden. Der einfachste Weg ist eine Schleife, mit der jedes Element der Auflistung einzeln überprüft wird. Dieser Lösungsansatz ist zwar oft langsam, kann aber ohne Mühe in allen Programmiersprachen umgesetzt werden. Eine Besonderheit bei der Entwicklung mit Swift sind hingegen Prädikate​, mit deren Hilfe die gleiche Aufgabe viel einfacher und schneller erledigt werden kann. Die Klasse NSPredicate​ aus dem Foundation Framework ermöglicht es, aus einer Auflistung gezielt die Objekte auswählen, die den Vorgaben entsprechen.

Um Prädikate und die Klasse NSPredicate in der Praxis ausprobieren zu können, benötigen wir im Projekt eine Liste mit Daten, die gefiltert werden kann, und wir können in den folgenden Beispielen auf unsere Klasse Truck zurückgreifen. Erstellen Sie ein Array, wie im folgenden Listing zu sehen, und füllen Sie es mit unterschiedlichen LKW-Typen. Sie können die Liste problemlos um zusätzliche Einträge mit anderen Eigenschaften erweitern. Je mehr Objekte Sie dem Array hinzufügen, desto eindrucksvoller wird das Ergebnis aussehen.

var truckArray = [Truck]()
 
var truck = Truck()
truck.make = "Manyroads"
truck.color = "Blau"
truck.wheels = 4
truckArray.append(truck)
 
truck = Truck()
truck.make = "Heavylift"
truck.color = "Silber"
truck.wheels = 4
truckArray.append(truck)
 
truck = Truck()
truck.make = "Manyroads"
truck.color = "Schwarz"
truck.wheels = 6
truckArray.append(truck)
 
truck = Truck()
truck.make = "Drivealot"
truck.color = "Rot"
truck.wheels = 6
truckArray.append(truck)
 
truck = Truck()
truck.make = "Cargoking"
truck.color = "Rot"
truck.wheels = 6
truckArray.append(truck)

Nachdem die Liste gefüllt wurde, können wir mit der Arbeit beginnen. Zwei LKW in der Liste sind vom Hersteller Manyroads und unsere erste Aufgabe soll darin bestehen, genau die zwei Fahrzeuge mithilfe eines Prädikats zu ermitteln. Die Definition des NSPredicate-Objekts geschieht mit einer Zeichenkette und ist in diesem Beispiel nicht kompliziert. Das tatsächliche Filtern wird anschließend über den Aufruf der filter-Methode des Arrays ausgeführt, die ein neues Array erzeugt, das ausschließlich die gesuchten LKW enthält.

// Ein Predicate für die Marke definieren
let nameFilter = NSPredicate(format: "make == 'Manyroads'")
 
// Den Filter anwenden und ein neues Array füllen
let filteredTrucks 
  = truckArray.filter {nameFilter.evaluateWithObject($0)}
 
// Das gefilterte Ergebnis ausgeben
for singleTruck in filteredTrucks
{
    print("\(singleTruck.make!) \(singleTruck.color!)")
}

In manchen Situationen möchte man vielleicht kein neues Array erzeugen, sondern nur prüfen, ob ein Objekt den im Prädikat angegebenen Bedingungen entspricht. Die Methode evaluateWithObject der Klasse NSPredicate erlaubt diese Überprüfung. Mit einer Schleife können wir dann leicht kontrollieren, welches Fahrzeug vom Hersteller Manyroads ist und welches nicht.

let nameFilter = NSPredicate(format: "make == 'Manyroads'")
 
for singleTruck in truckArray
{
    if nameFilter.evaluateWithObject(singleTruck)
    {
        print(String(format: "Gesuchtes Fahrzeug: %@ in %@",
         singleTruck.make!, singleTruck.color! ))
    }
    else
    {
        print(String(format: "Ein anderes Fahrzeug: %@ in %@",
          singleTruck.make!, singleTruck.color!))
    }
}

Die Definition eines Prädikats erinnert an eine Anweisung der Datenbanksprache SQL, weil für die Bedingungen eine ähnliche Syntax verwendet wird. Da es sich um eine Zeichenkette handelt, treten Probleme in der Regel erst zur Laufzeit auf. Der Compiler kann ein Prädikat nicht überprüfen. In manchen Situationen ist ein NSPredicate jedoch tolerant und erlaubt die Definition eines Vergleichs mit nur einem Gleichheitszeichen. Sie sollten sich diese Schreibweise aber besser gar nicht erst angewöhnen!

let nameFilter = NSPredicate(format: "make = 'Manyroads'")

33.4  Erweiterte Vergleiche, logische Operatoren und Closures

Möchte man die LKW anhand ihres Herstellers in Gruppen von A bis Z einteilen, kann das über ein Prädikat mit BEGINSWITH realisiert werden, das nicht den kompletten Namen, sondern den Anfang der Zeichenkette vergleicht. Die Groß- und Kleinschreibung kann über den zusätzlichen Operator [c] ignoriert werden und Buchstaben mit einem Akzent, wie Ê oder Â, werden durch [d] korrekt eingeordnet. Benötigten Sie beide Optionen, was vermutlich bei den meisten Textvergleichen der Fall sein wird, können Sie die Operatoren zu einem [cd] kombinieren.

// Alle Hersteller, die mit einem D oder d beginnen
let nameFilter = NSPredicate(format:
  "make BEGINSWITH [cd] %@","d")

In vielen Beispielen, die zur Erklärung von BEGINSWITH dienen, wird die angegebene Eigenschaft mit einem einzelnen Zeichen verglichen, obwohl der Vergleich mit mehreren Zeichen problemlos möglich ist. Das Gegenstück zu BEGINSWITH ist ENDSWITH und vergleicht die Zeichen am Ende von Strings. Mit CONTAINS können Sie prüfen, ob sich Zeichen an beliebiger Stelle im Text befinden.

Ähnlich wie bei einer if-Struktur können in einem Prädikat boolesche Operatoren verwendet werden, wenn NSPredicate mehrere Bedingungen abbilden soll. Als Ergänzung zu den Operatoren &&, || und ! kann innerhalb des Prädikats mit den Begriffen AND, OR und NOT gearbeitet werden. Das folgende Prädikat filtert sämtliche Objekte, bei denen die Eigenschaft make ein »y« enthält oder die Farbe des Fahrzeuges Rot ist.

// Hersteller mit einem Y oder mit roter Farbe
let nameFilter = NSPredicate(format:
 "make CONTAINS [c] %@ OR color CONTAINS [c] %@","y", "rot")

Alle LKW vom Hersteller Manyroads mit sechs oder mehr Reifen liefert die folgende Definition. Ob statt eines AND ein && verwendet wird, hat auf das Suchergebnis keinen Einfluss, denn beide Operatoren arbeiten exakt gleich. Die Programmierung mit AND und OR signalisiert allerdings viel besser die Nähe zu SQL. So erhalten wir eine gut sichtbare Trennung zwischen der Logik der Prädikate und der Programmlogik. Indem wir für alle Schlüsselwörter wie CONTAINS oder BEGINSWITH ausschließlich Großbuchstaben verwenden, wird das Prädikat besser lesbar.

let nameFilter = NSPredicate(
  format:"wheels >= 6  && make == 'Manyroads'")

Ist die Bedingung für ein Prädikat umfangreich, ist es oft der einfachste Weg, das NSPredicate mit einer Closure​ anzulegen. Weil im zugehörigen Block sämtliche Swift-Anweisungen zur Verfügung stehen, können umfangreiche Bedingungen leicht umgesetzt werden. Im folgenden Listing wird ein Prädikat definiert, das alle Fahrzeuge filtert, die vier oder weniger Reifen haben oder deren Farbe nur drei Zeichen lang ist. Der Parameter evaluatedObject muss für einen gültigen Vergleich zunächst von AnyObject wieder in ein Truck-Objekt umgewandelt werden. Ist die Bedingung erfüllt, gibt die Closure ein true zurück, im anderen Fall ist der Rückgabewert false. Der Parameter bindings wird in dieser Closure nicht benötigt. Wie bei allen Closure können auch für ein Prädikat Variablen aus dem übergeordneten Gültigkeitsbereich eingefangen werden.

// Maximale Anzahl von Reifen
let maxWheels = 4
// Maximale Anzahl von Zeichen
let maxCharacters = 3
 
var predicate =  NSPredicate
{
    (evaluatedObject, bindings) in
 
    if let truck = evaluatedObject as? Truck
    {
        if truck.color?.characters.count == maxCharacters ||
           truck.wheels <= maxWheels
        {
            return true
        }
    }
    return false
}
 
// Den Filter anwenden und ein neues Array füllen
let filteredTrucks 
  = truckArray.filter {predicate.evaluateWithObject($0)}
 
// Das gefilterte Ergebnis ausgeben
for singleTruck in filteredTrucks
{
    print("\(singleTruck.make!) \(singleTruck.color!)")
}

33.5  Prädikate mit regulären Ausdrücken

Vielleicht sind Ihnen reguläre Ausdrücke​ (englisch: Regular Expressions​) vertraut, mit denen sich ebenfalls Zeichenketten auf bestimmte Kriterien hin untersuchen lassen. Die zur Definition eines regulären Ausdrucks erforderliche Syntax ist im Vergleich zu Befehlen wie CONTAINS oder BEGINSWITH komplizierter, ermöglicht zum Ausgleich aber eine große Flexibilität für mögliche Filter. Die folgenden Listings zeigen einige einfache Anwendungsfälle. Im ersten Beispiel werden alle Fahrzeuge aus dem Array herausgefiltert, deren Farbe mit »S« beginnt. In unserer Liste sind das Silber und Schwarz.

let predicate = NSPredicate(format:"color MATCHES 'S.*' ")
 
// Den Filter anwenden und ein neues Array füllen
let filteredTrucks 
  = truckArray.filter {predicate.evaluateWithObject($0)}
 
// Das gefilterte Ergebnis ausgeben
for singleTruck in filteredTrucks
{
    print("\(singleTruck.make!) \(singleTruck.color!)")
}

Die LKW der Hersteller Divealot und Heavylift sind das Ergebnis der folgenden Definition. Ihre Namen enden mit einem kleinen t.

let predicate = NSPredicate(format:"make MATCHES '.*t' ")

Eine Suche nach Zeichen an einer beliebigen Stelle im Text zeigt das folgende Beispiel, bei dem allerdings nur kleine Buchstaben gültig sind. Fahrzeuge der Marke Drivealot werden nicht ausgegeben.

let predicate = NSPredicate(format:"make MATCHES '.*d.*' ")

Das folgende Prädikat liefert alle Marken, die mit einem großen C beginnen. Das ist in unsere Liste Cargoking. Ändern Sie das Zeichen zu einem kleinen c, werden keine Übereinstimmungen mehr gefunden.

let predicate = NSPredicate(format:"make MATCHES 'C.*' ")

Alle LKW, deren Markenname mit einem Großbuchstaben aus dem Bereich A bis L beginnt, werden durch die nächste Definition ermittelt. Fahrzeuge von Manyroads fehlen dann in der Ergebnismenge.

let predicate = NSPredicate(format:"make MATCHES '[A-L].*' ")

Reguläre Ausdrücke können sehr komplex werden, und es ist an dieser Stelle leider nicht möglich, dieses Thema umfassend zu behandeln. Falls Ihnen reguläre Ausdrücke gefallen, werden Sie im Internet ohne Mühe reichhaltige Informationen finden. Einige Fachbücher, manche davon mit beachtlichem Umfang, haben sich ebenfalls dieser Thematik angenommen.

33.6  Daten filtern für Tabellen

Nach viel Theorie wollen wir uns jetzt einer möglichen Verwendung in einer iOS-App zuwenden. Ein einfacher Weg, die Filter- und Suchfunktionen von Swift in der Praxis auszuprobieren, lässt sich mit einem UITableView​-Steuerelement realisieren. Wenn die Anwendung startet oder noch kein Suchkriterium zugewiesen wurde, zeigt die Tabelle alle Objekte ihrer Datenquelle an. Nach der Eingabe eines Filters beschränkt sich die Ausgabe auf die übereinstimmenden Elemente. Im Daten-Model müssen wir jetzt zwei Listen verwalten. Eine Liste mit allen Objekten und eine gefilterte Liste, die nur jene Objekte enthält, die auf der grafischen Oberfläche angezeigt werden sollen. Leicht lassen sich die Daten mit einer Repository​-Klasse verwalten. Sie enthält neben den auszugebenden Daten-Objekten zusätzliche Methoden, um die Ausgabe zu filtern und zu sortieren. Für die Eingabe der Suchkriterien gibt es im UIKit Framework sogar ein spezielles Eingabefeld-Steuerelement, das direkt oberhalb eines UITableView angedockt werden kann. Die Einstellungen-App von Apple zeigt gut, wie die grafische Oberfläche einer solchen Anwendung aufgebaut wird.

In einer leicht verständlichen App wollen wir eine Liste von Städtenamen filtern und sortieren, und das Projekt soll CityList heißen. Für die Vorlage verwenden wir den Projekttyp Single View Application. Als Erstes müssen wir den View Controller im Storyboard austauschen. Löschen Sie die aktuelle Ansicht und ziehen Sie anschließend die Vorlage Table View Controller aus der Object Library in den Arbeitsbereich. Damit das Storyboard mit dieser Szene startet, muss im Attributes Inspector die Eigenschaft Is Initial View Controller gesetzt werden. Sobald der große Pfeil auf die Szene zeigt, ist alles in Ordnung. Mit einer Warnung verlangt die Entwicklungsumgebung nach einem Identifier für die Prototypen-Zelle im Table View. Nennen Sie die Zelle Cell.

Wenn Sie das Projekt kompilieren und ausführen, werden Sie im Simulator ein weißes Fenster mit den vertrauten grauen Trennlinien eines Tabellen-Steuerelements sehen. Jetzt können wir mit der eigentlichen Arbeit beginnen.

Wie zuvor angedeutet, werden wir in diesem Projekt auf ein komplexes Daten-Model verzichten und in unserer Repository-Klasse lediglich Auflistungen von Zeichenketten mit Städtenamen verwalten. Erstellen Sie zunächst eine neue Klasse mit dem Namen CityRepository und fügen Sie in der Implementierung Eigenschaften für zwei Arrays hinzu. cityArray ist die unveränderliche Auflistung aller Städtenamen und wird bei der Initialisierung der Klasse mit Inhalt gefüllt. Die gefilterte Liste filteredCityArray ist eine Variable, da sich ihr Inhalt zur Laufzeit, abhängig von den Benutzereingaben, ändern soll. Würde man nach einem Namen suchen, der in der Liste aller Städte nicht zu finden ist, wäre die gefilterte Liste leer.

import Foundation
 
class CityRepository
{
    // Die Liste aller Städte
    let citiesArray:[String]
    // Die gefilterte Liste
    var filteredCitiesArray:[String]
}

Die im nächsten Listing gezeigte Liste mit Städtenamen können Sie nach Ihren Wünschen ändern und erweitern. Je mehr Objekte dem Array hinzugefügt werden, desto eindrucksvoller ist das Programm. Die Methode resetFilter überträgt sämtliche Objekte aus dem citiesArray in das filteredCitiesArray und stellt somit alle Namen zur Anzeige zur Verfügung. Diese Methode benötigen wir beim Start der App und nachdem der Anwender einen zuvor eingetragenen Filter entfernt hat. Wir müssen uns nicht die Mühe machen, die Orte im Code anhand ihrer Namen zu sortieren. Diese Aufgabe übernimmt das Programm durch den Aufruf sortInPlace.

init()
{
    citiesArray = ["London", "Berlin", "Paris",
    "Wien", "Istanbul", "Dallas", "Stockholm",
    "New York", "Hong Kong", "Bern", "Athen",
    "Kiew", "Frankfurt", "Buenos Aires"]
 
    filteredCitiesArray = [String]()
    self.resetFilter()
}
 
func resetFilter()
{
    // Eventuell vorhandene Objekte entfernen
    self.filteredCitiesArray.removeAll()
 
    // Alle Elemente aus dem Array citiesArray
    // in das Array filteredCitiesArray übertragen
    for city in citiesArray
    {
        filteredCitiesArray.append(city)
    }
 
    // Das Array sortieren
    filteredCitiesArray.sortInPlace(
     {$0.caseInsensitiveCompare($1)
      == NSComparisonResult.OrderedAscending })
}

Die Methode zur Filterung der Städtenamen soll filter heißen und ist vom Aufbau her ähnlich der Methode resetFilter. Erneut kommt eine for-Schleife​ zum Einsatz, um die Objekte in die Liste der gefilterten Städte zu übertragen. Durch ein zuvor definiertes Prädikat wird zunächst geprüft, ob die als Parameter übergebene Zeichenkette im Namen einer Stadt zu finden ist. Statt eines Vergleichs mit CONTAINS könnte mit BEGINSWITH verglichen werden, woraufhin nur noch am Anfang des Namens nach Übereinstimmungen gesucht wird. Nachdem das Array gefüllt wurde, kann das gefilterte Ergebnis mit sortInPlace sortiert werden.

func filter(searchString:String)
{
    let predicate = NSPredicate(
      format: "self CONTAINS [cd] %@", searchString)
 
    self.filteredCitiesArray.removeAll()
 
    // Alle Elemente aus dem Array citiesArray
    // in das Array filteredCitiesArray übertragen
    for city in citiesArray
    {
        if predicate.evaluateWithObject(city)
        {
            filteredCitiesArray.append(city)
        }
    }
 
    filteredCitiesArray.sortInPlace({
      $0.caseInsensitiveCompare($1)
      == NSComparisonResult.OrderedAscending })
}

Die zur Kommunikation zwischen Repository und Tabellen-View-Controller benötigten Methoden können wir mit kleinen Änderungen bei bekannten Beispielen übernehmen. itemsCount liefert die Anzahl der Elemente in der gefilterten Liste und itemAtIndex immer genau ein Objekt an der angegebenen Position.

func itemsCount() -> Int
{
    return self.filteredCitiesArray.count
}
 
func itemAtIndex(index:Int) -> String
{
    return self.filteredCitiesArray[index]
}

33.7  Listen für den Tabellen-View-Controller

Nachdem die Arbeit an unserem Repository abgeschlossen ist, sollten wir die Anwendung jetzt so weit vorbereiten, dass zumindest die Liste aller Städte schon auf der grafischen Oberfläche angezeigt wird. Eine von UITableViewController​ abgeleitete Klasse mit dem Namen CityTableViewController soll der View Controller der Szene werden und unser CityRepository wird innerhalb der Klasse eine Eigenschaft.

import UIKit
 
class CityTableViewController: UITableViewController
{
    var cityRepository:CityRepository?

    override func viewDidLoad()
    {
        cityRepository = CityRepository()
        super.viewDidLoad()
    }
...

Die von Xcode für den UITableView vorbereiteten Methoden können wir nach dem bekannten Muster mit Leben füllen. Unsere Liste hat nur eine Sektion und die Anzahl der Zeilen entspricht der Anzahl der Zeichenketten im Array. In der Methode tableView(_: cellForRowAtIndexPath:) holen wir uns einen Eintrag aus unserem Repository und weisen den Namen der Stadt dem textLabel der Tabellenzelle zu.

override func numberOfSectionsInTableView(
  tableView: UITableView) -> Int
{
    // Nur eine Sektion für die Tabelle
    return 1
}
 
override func tableView(tableView: UITableView,
  numberOfRowsInSection section: Int) -> Int
{
    // Die Anzahl der Zeilen entspricht der Anzahl
    // der Objekte im Repository
    return self.cityRepository!.itemsCount()
}
 
override func tableView(tableView: UITableView,
  cellForRowAtIndexPath indexPath: NSIndexPath)
  -> UITableViewCell
{
    let cell = tableView.dequeueReusableCellWithIdentifier(
    "Cell", forIndexPath: indexPath)
    // Ein Objekt aus dem Repository holen und der
    // Zelle zuweisen
    let city = self.cityRepository!.itemAtIndex(indexPath.row)
    cell.textLabel?.text = city
 
    return cell
}

Vor einem ersten Test müssen wir die Identität der View-Controller-Klasse im Storyboaod anpassen. Eine Aufgabe für den Identity Inspector. Markieren Sie den orangefarbenen View-Controller-Platzhalter im Dock der Szene oder in der Seitenleiste und ändern Sie die Eigenschaft Class in unsere Klasse CityTableViewController.

Die Verbindungen für Delegate und DataSource hat die Entwicklungsumgebung für uns angelegt, trotzdem sollten wir uns einen Augenblick Zeit nehmen und die Einstellungen im Connections Inspector kontrollieren. Reagiert eine Tabelle nicht auf Aktionen des Benutzers oder zeigt sie keine Daten, kann dort der Fehler liegen. In älteren Versionen von Xcode mussten Entwickler die Verbindungen selbst anlegen. Die grafische Oberfläche, der View, wurde ebenfalls von Xcode mit der Eigenschaft view der Controller-Klasse verbunden.

Jetzt können wir endlich die App ausprobieren, und wie geplant zeigt uns der Tabellen-View-Controller eine sortierte Liste aller Städtenamen, die wir im Array hinterlegt haben.

33.8  Suchen mit dem UISearchController

​Soll in einer App gesucht werden, ist seit iOS 8 die Klasse UISearchController​ der richtige Ansprechpartner. Er übernimmt die Aufgabe, die Suchleiste​ über der Tabelle einzublenden, die Sie vermutlich aus anderen Apps kennen. Leider kann das Steuerelement in der aktuellen Xcode-Version nicht mit dem Interface Builder eingefügt werden. Wir müssen stattdessen eine Instanz im Programmcode erzeugen. Im ersten Schritt erhält unsere Klasse CityTableView deshalb eine Eigenschaft vom Typ UISearchController. Die Konfiguration eines neuen Objekts folgt in viewDidLoad. Für eine reibungslose Kommunikation zwischen dem UISearchController und unserer Controller-Klasse sorgt das UISearchResultsUpdating-Protokoll.

class CityTableViewController: UITableViewController, 
  UISearchResultsUpdating
{
    var cityRepository:CityRepository?
    var searchController:UISearchController?
 
    override func viewDidLoad()
    {
        self.cityRepository = CityRepository()
 
        self.searchController 
          = UISearchController(searchResultsController: nil)
        self.searchController!.searchResultsUpdater 
          = self
        self.searchController!.dimsBackgroundDuringPresentation
          = false
        self.definesPresentationContext = true
        self.tableView.tableHeaderView 
         = searchController?.searchBar
 
        super.viewDidLoad()
    }
...

Die Konfiguration eines UISearchController ist zwar umfangreich, aber nicht schwierig. Bei der Initialisierung wird der Instanz für den Parameter searchResultsController der Wert nil übergeben, was zur Folge hat, dass wir die aktuelle Ansicht auch zur Anzeige der Suchergebnisse verwenden müssen. Alternativ könnte ein anderer Controller übergeben werden. Mit der Eigenschaft searchResultsUpdater wird bestimmt, welches Objekt Benachrichtigungen enthält, wenn der Nutzer in die Suchleiste schreibt. In unserem Fall ist es die Controller-Klasse CityTableViewController, also self. Möglich wäre jede beliebige Klasse, die das UISearchResultsUpdating-Protokoll implementiert. Der Wert true für die Eigenschaft definesPresentationContext verhindert, dass die Suchleiste sichtbar bleibt, wenn der Nutzer zu einer anderen Szene navigiert. Mit der Eigenschaft dimsBackgroundDuringPresentation wird festgelegt, ob der aktuelle View während einer Eingabe in die Suchleiste abgedunkelt wird.

Zur Umsetzung des UISearchResultsUpdating-Protokolls müssen wir unsere Controller-Klasse um eine Methode erweitern. updateSearchResultsForSearchController wird aufgerufen, wenn der Nutzer in die Suchleiste schreibt oder wenn die Suche durch die Schaltfläche Cancel abgebrochen wurde. Abhängig von der Anzahl der eingegebenen Zeichen können wir dann entscheiden, ob der Tabelleninhalt gefiltert wird oder nicht. Immer erforderlich ist der Aufruf von reloadData. Mit ihm wird die Tabelle aufgefordert, ihre Daten neu zu laden. Viel mehr müssen wir nicht tun. Die Logik zum Filtern haben wir zuvor in unserem Repository implementiert.

func updateSearchResultsForSearchController(
  searchController: UISearchController)
{
    // Der in die Suchleiste eingegebene Text
    let searchText = searchController.searchBar.text!
 
    if searchText.characters.count > 0
    {
        // Inhalt filtern
        self.cityRepository!.filter(searchText)
    }
    else
    {
        // Filter zurücksetzen
        self.cityRepository!.resetFilter()
    }
 
    self.tableView.reloadData()
}

Jetzt funktioniert unser Programm wie geplant, allerdings sind noch einige Schönheitskorrekturen anzuraten. Die Statusleiste überdeckt die Suchleiste und macht die App unansehnlich. Besser wäre es, die Statusleiste in der App komplett auszublenden und mit zwei Einträgen in der Info.plist​ ist das tatsächlich möglich. Erweitern Sie die Datei um den Key UIStatusBarHidden mit dem Wert true und um UIViewControllerBasedStatusBarAppearance mit dem Key false.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>UIStatusBarHidden</key>
    <true/>
    <key>UIViewControllerBasedStatusBarAppearance</key>
    <false/>
...

Zusätzliche Anpassungen können in der viewDidLoad-Methode der View-Controller-Klasse vorgenommen werden. Beispielsweise die Farben der Suchleiste und der Platzhaltertext für das Eingabefeld.

let backgroundColor = UIColor(colorLiteralRed: 0.7,
  green: 0.7, blue: 0.8, alpha: 1.0)
let tintColor = UIColor(colorLiteralRed: 1.0,
  green: 0.0, blue: 0.0, alpha: 1.0)
 
// Hintergrundfarbe der Suchleiste
self.searchController?.searchBar.barTintColor 
  = backgroundColor
// Buttontextfarbe und Cursorfarbe
self.searchController?.searchBar.tintColor 
  = tintColor
// Platzhaltertext für die Suchleiste
self.searchController?.searchBar.placeholder = "Suchen ..."

Wollte man aus dem Suchergebnis in eine Detailansicht wechseln, wäre das ohne Probleme möglich. Methoden wie tableView(_: didSelectRowAtIndexPath:) stehen im CityTableViewController weiterhin zur Verfügung. Der indexPath bezieht sich im kompletten Tabellen-View-Controller immer auf einen Eintrag aus dem filteredCitiesArray der Repository-Klasse. Ob die Auflistung mit allen Städtenamen gefüllt ist oder einen Teil enthält, wird über die Filtermethode gesteuert. Versuchen Sie, das Projekt eigenständig um eine Detailansicht zu erweitern.

Referenzkarte Swift 2.0

Variablen und Konstanten
// Variablen und Konstanten
var variableValue = 3.1415
variableValue = 3.0
 
let constValue = 42
// Neue Zuweisung nicht möglich
// constValue = 50
Fallunterscheidungen
var salary = 10000
 
if salary > 15000
{
    print("Zu viel")
}
else if salary < 10000
{
    print("Zu wenig")
}
else
{
    print("Ok")
}
 
var index = 4
 
switch index
{
    case 1:
        print("Index ist 1")
    case 2:
        print("Index ist 2")
    case 3...5:
        print("Index liegt zwischen 3 und 5")
    case 6:
        print("Index ist 6")
        fallthrough
    default:
        print("Index liegt nicht zwischen 1 bis 5")
}
Schleifen
for var index = 0; index <= 5; index++
{
    print(index) // Ausgabe von 0 bis 5
}
 
for index in 0...5 // Closed-Range
{
    print(index) // Ausgabe von 0 bis 5
}
 
for index in 0..<5 // Half-Closed-Range
{
    print(index) // Ausgabe von 0 bis 4
}
 
for index in (5...10).reverse()
{
    print(index) // Ausgabe von 10 bis 5
}
 
var access = 1
repeat
{
    print(access) // Ausgabe von 1 bis 9
    access++
}
while access < 10
Methoden/Funktionen
// Ohne Parameter und ohne Rückgabewert
func doSomething()
{
    print("Hello World!")
}
 
doSomething()
 
// Mit einem Double als Parameter und einem Double
// als Rückgabewert
func doSomething(value:Double) -> Double
{
    return value * 2.0
}
 
var twice = doSomething(4.5)
 
// Mit zwei benannten Parametern
// und einem Double als Rückgabewert
func doSomething(
  firstValue first:Double, secondValue second:Double) -> Double
{
   return first + second
}
 
var sum = doSomething(firstValue: 3.2, secondValue: 4.7)
Array
var cities:[String] = ["Rom","Paris","Berlin"]
cities.append("London")
 
for city in cities
{
    print(city) // Ausgabe alle Städtenamen
}
 
var count = cities.count // Anzahl der Elemente
Dictionary
var animals:[Int: String] = [11:"Hund", 22:"Katze", 33:"Maus"]
animals[22] = "Elefant" // Element ersetzen
animals[99] = "Huhn" // Element anfügen
 
print(animals[22]) // Ausgabe "Optional (Elefant)"
print(animals[99]) // Ausgabe "Optional (Huhn)"
 
animals[11] = nil // Element entfernen
Zeichenketten
var firstName = "Mike"
var lastName = "Müller"
// String Interpolation
print("Mein Name ist \(firstName) \(lastName).")
 
// Zahlenwerte formatieren
var numeric = 3.34983632
var num = String(format:"%.2f", numeric) // Ausgabe 3.35
Enumerationen
enum Color
{
    case Red
    case Green
    case Blue
}
var exterior:Color = Color.Green
Klassen
class Person
{
    // Eigenschaften
    var firstName:String
    var lastName:String

    init()
    {
        // Eigenschaften initialisieren
        firstName = ""
        lastName = ""
    }
}
 
// Klasseninstanz erzeugen und
// Eigenschaften zuweisen
var pers = Person()
pers.firstName = "Mike"
pers.lastName = "Müller"
Fehlerbehandlung mit try-catch
// Eigene Fehlertypen definieren
enum CalculationError : ErrorType
{
    case DivideByZero
    case OtherError
}
 
// Funktion kann einen Fehler zurückgeben
func divide(dividend:Int, divisor:Int) throws -> Int
{
    guard divisor > 0 else
    {
        throw CalculationError.DivideByZero
    }
    return dividend / divisor
}
 
// Funktionsaufruf und Fehlerbehandlung
do
{
    var result = try divide(100, divisor: 0)
}
catch(CalculationError.DivideByZero)
{
    print("Es wurde versucht, durch null zu teilen")
}
catch
{
    print("Ein anderer Fehler ist aufgetreten")
}