Ein iOS-Entwicklerhandbuch: Von Objective-C zu Learning Swift
Veröffentlicht: 2022-03-112008 kündigte Apple das iPhone SDK 2.0 an und veröffentlichte es. Dieses Ereignis löste eine weitere Revolution in der Softwareentwicklung aus, und eine neue Generation von Entwicklern wurde geboren. Sie werden jetzt als iOS-Entwickler anerkannt.
Viele dieser Entwickler hatten Objective-C noch nie zuvor verwendet, und das war die erste Herausforderung, die Apple ihnen stellte. Trotz ungewohnter Syntax und manueller Speicherverwaltung war es enorm erfolgreich und trug dazu bei, den App Store mit Zehntausenden von Apps zu füllen. Apple hat Objective-C mit jeder Version kontinuierlich verbessert, Blöcke und Literale hinzugefügt, die Speicherverwaltung mit automatischer Referenzzählung und viele andere Merkmale hinzugefügt, die auf eine moderne Programmiersprache hinweisen.
Und nach 6 Jahren Verbesserung und Arbeit an Objective-C beschloss Apple, Entwicklern eine weitere Herausforderung zu stellen. Wieder einmal müssen iOS-Entwickler eine neue Programmiersprache lernen: Swift . Swift entfernt die unsichere Zeigerverwaltung und führt leistungsstarke neue Funktionen ein, während die Interaktion mit Objective-C und C beibehalten wird.
Swift 1.0 ist bereits eine stabile und starke Entwicklungsplattform, die sich in den kommenden Jahren sicherlich auf interessante Weise weiterentwickeln wird. Es ist ein perfekter Moment, um mit der Erforschung dieser neuen Sprache zu beginnen, da sie offensichtlich die Zukunft der iOS-Entwicklung ist.
Der Zweck dieses Tutorials besteht darin, Objective-C-Entwicklern einen schnellen Überblick über die neuen Funktionen der Swift-Sprache zu geben und Ihnen dabei zu helfen, den nächsten Schritt zu tun und Swift in Ihrer täglichen Arbeit zu übernehmen. Ich werde nicht zu viel Zeit damit verbringen, Objective-C zu erklären, und ich gehe davon aus, dass Sie mit der iOS-Entwicklung vertraut sind.
Swift vs. Objective-C ausprobieren
Um Swift zu erkunden, müssen Sie lediglich XCode aus dem App Store herunterladen und einen Spielplatz zum Experimentieren erstellen. Alle in diesem Artikel erwähnten Beispiele werden auf diese Weise ausgeführt.
Die Swift-Homepage von Apple ist die beste Referenz zum Erlernen der Swift-Programmierung. Sie werden feststellen, dass es von unschätzbarem Wert ist, und ich glaube, dass Sie oft hierher zurückkehren werden, bis Sie mit der Entwicklung von Swift auf dem neuesten Stand sind.
Variablen und Konstanten
Das Deklarieren einer Variablen in Swift erfolgt mit dem Schlüsselwort var .
var x = 1 var s = "Hello" Sie werden feststellen, dass zwei Variablen x und s von unterschiedlichem Typ sind. x ist eine ganze Zahl, während s ein String ist. Swift ist eine typsichere Sprache und leitet Variablentypen aus dem zugewiesenen Wert ab. Wenn Sie Ihren Code lesbarer machen möchten, können Sie optional den Variablentyp annotieren:
var y: Int y = 2 Konstanten sind ähnlich, aber Sie deklarieren sie mit let anstelle von var . Der Wert einer Konstanten muss zur Kompilierzeit nicht bekannt sein, aber Sie müssen ihr genau einmal einen Wert zuweisen.
let c1 = 1 // Constant known at compile time var v = arc4random() let c2 = v // Constant known only at run timeWie ihr Name schon sagt, sind sie unveränderlich, sodass der folgende Code einen Kompilierungsfehler verursacht.
let c = 1 c = 3 // errorAndere Typen können auch als konstant deklariert werden. Der folgende Code deklariert beispielsweise ein Array als Konstante, und wenn Sie versuchen, eines der Elemente zu ändern, meldet der Swift-Compiler einen Fehler:
var arr2 = [4, 5, 6] arr2[0] = 8 print (arr2) // [8, 5, 6] let arr = [1, 2, 3] a[0] = 5 // errorOptionen
Konstanten müssen initialisiert werden, wenn sie deklariert werden, und Variablen müssen vor der Verwendung initialisiert werden. Wo ist also das Objective-C- nil -Äquivalent? Swift führt optionale Werte ein. Optionale Werte können einen Wert haben oder nil sein. Wenn Sie sich den folgenden Code ansehen, werden Sie feststellen, dass x der Optional Wert 2014 zugewiesen wurde. Das bedeutet, dass dem Swift-Compiler bewusst war, dass x auch nil sein könnte.
var s = "2014" var x = s.toInt() print(x) // Optional(2014) Wenn Sie diesen Code ändern und s den Wert "abc" zuweisen, der nicht in eine Ganzzahl konvertiert werden kann, werden Sie feststellen, dass x jetzt ein nil ist.
var s = "abc" var x = s.toInt() print(x) // nil Der Rückgabetyp der Funktion toInt() ist Int? , was ein optionaler Int ist. Versuchen wir, eine Standardfunktion für x aufzurufen:
var x = "2014".toInt() print(x.successor()) // error Der Compiler signalisiert einen Fehler, da x optional ist und möglicherweise nil sein könnte . Wir müssen x zuerst testen und sicherstellen, dass die successor für eine reelle Zahl und nicht für einen nil aufgerufen wird:
var x = "2014".toInt() if x != nil { print(x!.successor()) // 2015 } Beachten Sie, dass wir x auspacken müssen, indem wir ein Ausrufezeichen (!) anhängen . Wenn wir sicher sind, dass x einen Wert enthält, können wir darauf zugreifen. Andernfalls erhalten wir einen Laufzeitfehler. Wir können auch das tun, was Swift als optionale Bindung bezeichnet, indem wir die optionale in eine nicht optionale Variable umwandeln
let x = "123".toInt() if let y = x { print(y) } Der Code in der if -Anweisung wird nur ausgeführt, wenn x einen Wert hat und ihn y . Beachten Sie, dass wir y nicht auspacken müssen, sein Typ ist nicht optional, da wir wissen, dass x nicht nil ist.
Sehen Sie sich das Swift-Tutorial von Apple an, um weitere Details zu Optionen und netten Funktionen wie optionaler Verkettung zu lesen
String-Interpolation
In Objective-C erfolgt die Formatierung von Strings normalerweise mit der Methode stringWithFormat:
NSString *user = @"Gabriel"; int days = 3; NSString *s = [NSString stringWithFormat:@"posted by %@ (%d days ago)", user, days];Swift hat eine Funktion namens String-Interpolation , um dasselbe zu tun, aber es ist kompakter und einfacher zu lesen:
let user = "Gabriel" let days = 3 let s = "posted by \(user) \(days) ago"Sie können auch Ausdrücke verwenden:
let width = 2 let height = 3 let s = "Area for square with sides \(width) and \(height) is \(width*height)"Um mehr über die String-Interpolation von Swift und andere neue Funktionen zu erfahren, klicken Sie hier.
Funktionen
Die Funktionsdefinition in Swift unterscheidet sich von C. Eine beispielhafte Funktionsdefinition finden Sie unten:
func someFunction(s:String, i: Int) -> Bool { ... // code }Swift-Funktionen sind erstklassige Typen . Das bedeutet, dass Sie Variablen Funktionen zuweisen, sie als Parameter an andere Funktionen übergeben oder sie zu Rückgabetypen machen können:
func stringLength(s:String) -> Int { return countElements(s) } func stringValue(s:String) -> Int { if let x = s.toInt() { return x } return 0 } func doSomething(f:String -> Int, s:String) -> Int { return f(s).successor() } let f1 = stringLength let f2 = stringValue doSomething(f1, "123") // 4 doSomething(f2, "123") // 124 Auch hier leitet Swift die Typen von f1 und f2 ( String -> Int ) ab, obwohl wir sie explizit hätten definieren können:
let f1:String -> Int = stringLengthFunktionen können auch andere Funktionen zurückgeben:
func compareGreaterThan(a: Int, b: Int) -> Bool { return a > b } func compareLessThan(a: Int, b: Int) -> Bool { return a < b } func comparator(greaterThan:Bool) -> (Int, Int) -> Bool { if greaterThan { return compareGreaterThan } else { return compareLessThan } } let f = comparator(true) println(f(5, 9))Eine Anleitung zu Funktionen in Swift finden Sie hier.
Aufzählungen
Aufzählungen in Swift sind viel mächtiger als in Objective-C. Als Swift-Strukturen können sie Methoden haben und werden als Wert übergeben:
enum MobileDevice : String { case iPhone = "iPhone", Andro, WP8 = "Windows Phone8", BB = "BlackBerry" func name() -> String { return self.toRaw() } } let m = MobileDevice.Android print(m.name()) // "Android" Im Gegensatz zu Objective-C können Swift-Enumerationen neben Ganzzahlen Strings, Zeichen oder Gleitkommazahlen als Werte für jedes Mitglied zuweisen. Die bequeme Methode toRaw() gibt den Wert zurück, der jedem Mitglied zugewiesen ist.
Aufzählungen können auch parametrisiert werden:
enum Location { case Address(street:String, city:String) case LatLon(lat:Float, lon:Float) func description() -> String { switch self { case let .Address(street, city): return street + ", " + city case let .LatLon(lat, lon): return "(\(lat), \(lon))" } } } let loc1 = Location.Address(street: "2070 Fell St", city: "San Francisco") let loc2 = Location.LatLon(lat: 23.117, lon: 45.899) print(loc1.description()) // "2070 Fell St, San Francisco" print(loc2.description()) // "(23.117, 45.988)"Weitere Informationen zu Aufzählungen finden Sie hier.

Tupel
Tupel gruppieren mehrere Werte zu einem einzigen zusammengesetzten Wert. Die Werte innerhalb eines Tupels können von beliebigem Typ sein und müssen nicht vom gleichen Typ sein.
let person = ("Gabriel", "Kirkpatrick") print(person.0) // GabrielSie können die einzelnen Tupelelemente auch benennen:
let person = (first: "Gabriel", last: "Kirkpatrick") print(person.first)Tupel sind äußerst praktisch als Rückgabetypen für Funktionen, die mehr als einen Wert zurückgeben müssen:
func intDivision(a: Int, b: Int) -> (quotient: Int, remainder: Int) { return (a/b, a%b) } print(intDivision(11, 3)) // (3, 2) let result = intDivision(15, 4) print(result.remainder) // 3Anders als in Objective-C unterstützt Swift den Musterabgleich in einer switch-Anweisung:
let complex = (2.0, 1.1) // real and imaginary parts switch complex { case (0, 0): println("Number is zero") case (_, 0): println("Number is real") default: println("Number is imaginary") } Im zweiten Fall ist uns der Realteil der Zahl egal, also verwenden wir ein _ , um irgendetwas zu finden. Sie können auch in jedem Fall nach zusätzlichen Bedingungen suchen. Dazu müssen wir die Musterwerte an Konstanten binden:
let complex = (2.0, 1.1) switch complex { case (0, 0): println("Number is zero") case (let a, 0) where a > 0: println("Number is real and positive") case (let a, 0) where a < 0: println("Number is real and negative") case (0, let b) where b != 0: println("Number has only imaginary part") case let (a, b): println("Number is imaginary with distance \(a*a + b*b)") }Beachten Sie, dass wir nur die Werte binden müssen, die wir im Vergleich oder in der case-Anweisung verwenden werden.
Um mehr über Tupel zu erfahren, gehen Sie hier.
Klassen und Strukturen
Im Gegensatz zu Objective-C müssen Sie bei Swift keine separaten Schnittstellen- und Implementierungsdateien für benutzerdefinierte Klassen und Strukturen erstellen. Wenn Sie Swift lernen, lernen Sie, eine Klasse oder Struktur in einer einzigen Datei zu definieren, und die externe Schnittstelle zu dieser Klasse oder Struktur wird automatisch für anderen Code zur Verfügung gestellt.
Klassen definieren
Klassendefinitionen sind sehr einfach:
class Bottle { var volume: Int = 1000 func description() -> String { return "This bottle has \(volume) ml" } } let b = Bottle() print(b.description())Wie Sie sehen können, befinden sich Deklaration und Implementierung in derselben Datei . Swift verwendet keine Header- und Implementierungsdateien mehr. Fügen wir unserem Beispiel ein Label hinzu:
class Bottle { var volume: Int = 1000 var label:String func description() -> String { return "This bottle of \(label) has \(volume) ml" } }Der Compiler wird sich beschweren, weil label eine nicht optionale Variable ist und keinen Wert enthält, wenn eine Flasche instanziiert wird. Wir müssen einen Initialisierer hinzufügen:
class Bottle { var volume: Int = 1000 var label:String init(label:String) { self.label = label } func description() -> String { return "This bottle of \(label) has \(volume) ml" } } Oder wir könnten den Optional Typ für eine Eigenschaft verwenden, die nicht initialisiert werden muss. Im folgenden Beispiel haben wir volume zu einer Optional Integer gemacht:
class Bottle { var volume: Int? var label:String init(label:String) { self.label = label } func description() -> String { if self.volume != nil { return "This bottle of \(label) has \(volume!) ml" } else { return "A bootle of \(label)" } } }Strukturen
Die Swift-Sprache hat auch structs , aber sie sind viel flexibler als in Objective-C. Das folgende Code-Tutorial definiert eine struct :
struct Seat { var row: Int var letter:String init (row: Int, letter:String) { self.row = row self.letter = letter } func description() -> String { return "\(row)-\(letter)" } }Wie Klassen in Swift können Strukturen Methoden, Eigenschaften und Initialisierer haben und Protokollen entsprechen. Der Hauptunterschied zwischen Klassen und Strukturen besteht darin, dass Klassen als Referenz übergeben werden, während Strukturen als Wert übergeben werden .
Dieses Beispiel zeigt das Übergeben von Klassen als Referenz:
let b = Bottle() print(b.description()) // "b" bottle has 1000 ml var b2 = b b.volume = 750 print(b2.description()) // "b" and "b2" bottles have 750 ml Wenn wir einen ähnlichen Fall mit struct versuchen, werden Sie feststellen, dass Variablen als Wert übergeben werden:
var s1 = Seat(row: 14, letter:"A") var s2 = s1 s1.letter = "B" print(s1.description()) // 14-B print(s2.description()) // 14-A Wann sollten wir struct und wann class verwenden? Verwenden Sie wie in Objective-C und C Strukturen, wenn Sie einige Werte gruppieren müssen, und erwarten Sie, dass sie kopiert und nicht referenziert werden. Beispielsweise komplexe Zahlen, 2D- oder 3D-Punkte oder RGB-Farben.
Eine Instanz einer Klasse wird traditionell als Objekt bezeichnet. Die Funktionalität von Swift-Klassen und -Strukturen ist jedoch viel näher als in anderen Sprachen, und viele Funktionalitäten können auf Instanzen einer Klasse oder eines Strukturtyps angewendet werden. Aus diesem Grund ist der allgemeinere Begriff, der in der Swift-Referenz verwendet wird, instance , was auf alle diese beiden zutrifft.
Lernen Sie hier die Grundlagen der Swift-Klassen und -Strukturen.
Eigenschaften
Wie wir bereits gesehen haben, werden Eigenschaften in Swift mit dem Schlüsselwort var innerhalb einer Klassen- oder Strukturdefinition deklariert. Wir können Konstanten auch mit einer let Anweisung deklarieren.
struct FixedPointNumber { var digits: Int let decimals: Int } var n = FixedPointNumber(digits: 12345, decimals: 2) n.digits = 4567 // ok n.decimals = 3 // error, decimals is a constant Denken Sie auch daran, dass Klasseneigenschaften stark referenziert werden, es sei denn, Sie stellen ihnen das weak Schlüsselwort voran. Es gibt jedoch einige Feinheiten mit schwachen nicht-optionalen Eigenschaften, also lesen Sie das Kapitel zur automatischen Referenzzählung in Apples Swift-Handbuch.
Berechnete Eigenschaften
Berechnete Eigenschaften speichern eigentlich keinen Wert. Stattdessen stellen sie einen Getter und einen optionalen Setter bereit, um andere Eigenschaften und Werte indirekt abzurufen und festzulegen.
Der folgende Code bietet ein Beispiel für einen berechneten Wert sign :
enum Sign { case Positive case Negative } struct SomeNumber { var number:Int var sign:Sign { get { if number < 0 { return Sign.Negative } else { return Sign.Positive } } set (newSign) { if (newSign == Sign.Negative) { self.number = -abs(self.number) } else { self.number = abs(self.number) } } } }Wir können auch schreibgeschützte Eigenschaften definieren, indem wir einfach einen Getter implementieren:
struct SomeNumber { var number:Int var isEven:Bool { get { return number % 2 == 0 } } }In Objective-C werden Eigenschaften normalerweise durch eine Instanzvariable unterstützt, die explizit deklariert oder automatisch vom Compiler erstellt wird. In Swift hingegen hat eine Eigenschaft keine entsprechende Instanzvariable . Das heißt, auf den Sicherungsspeicher einer Eigenschaft kann nicht direkt zugegriffen werden. Angenommen, wir haben dies in Objective-C
// .h @interface OnlyInitialString : NSObject @property(strong) NSString *string; @end // .m @implementation OnlyInitialString - (void)setString:(NSString *newString) { if (newString.length > 0) { _string = [newString substringToIndex:1]; } else { _string = @""; } } @endDa berechnete Eigenschaften in Swift keinen Hintergrundspeicher haben, müssen wir so etwas tun:
class OnlyInitialString { var initial:String = "" var string:String { set (newString) { if countElements(newString) > 0 { self.initial = newString.substringToIndex(advance(newString.startIndex, 1)) } else { self.initial = "" } } get { return self.initial } } }Eigenschaften werden hier näher erläutert
Fortgesetzt werden
Es gibt viele weitere wichtige neue Dinge in Swift zu lernen, wie Generics, Interaktion mit Objective-C-Bibliotheken, Closures, optionale Verkettung und Überladung von Operatoren. Ein einzelnes Tutorial kann eine neue Sprache nicht vollständig beschreiben, aber ich bin sicher, dass noch viel mehr über das Erlernen der Swift-Programmierung geschrieben werden wird. Ich glaube jedoch, dass diese schnelle Lektüre vielen Objective-C-Entwicklern helfen wird, die es nicht geschafft haben, Zeit zu finden und Details der Swift-Sprache zu lernen, auf den richtigen Weg zu kommen und sich vom Swift-Vogel zu neuen Höhen führen zu lassen.
