Was ist ein optionaler Wert in Swift?


267

Aus Apples Dokumentation :

Sie können ifund letzusammen verwenden, um mit möglicherweise fehlenden Werten zu arbeiten. Diese Werte werden als Option dargestellt. Ein optionaler Wert enthält entweder einen Wert oder enthält, nilum anzuzeigen, dass der Wert fehlt. Schreiben Sie ein Fragezeichen ( ?) nach dem Typ eines Werts, um den Wert als optional zu markieren.

Warum sollten Sie einen optionalen Wert verwenden?



1
Optional kann auch als Implementierung der Option / Vielleicht-Monade angesehen werden . Dieser Blog hier versucht gut zu erklären, was sonst ein schwieriges Konzept ist.
StuartLC

tldr: "Swift muss klar sein, wann ein Wert fehlen kann und wann er garantiert existiert." von Nevans King's exzellente Antwort unten
Jonatan

Antworten:


531

Ein optionales Element in Swift ist ein Typ, der entweder einen Wert oder keinen Wert enthalten kann. Optionale Optionen werden durch Anhängen von a ?an einen beliebigen Typ geschrieben:

var name: String? = "Bertie"

Optionals (zusammen mit Generics) sind eines der am schwierigsten zu verstehenden Swift-Konzepte. Aufgrund der Art und Weise, wie sie geschrieben und verwendet werden, ist es leicht, eine falsche Vorstellung davon zu bekommen, was sie sind. Vergleichen Sie die obige Option mit der Erstellung einer normalen Zeichenfolge:

var name: String = "Bertie" // No "?" after String

Aus der Syntax geht hervor, dass ein optionaler String einem normalen String sehr ähnlich ist. Es ist nicht. Ein optionaler String ist kein String mit aktivierter "optionaler" Einstellung. Es ist keine spezielle Sorte von String. Ein String und ein optionaler String sind völlig unterschiedliche Typen.

Hier ist das Wichtigste zu wissen: Ein optionales ist eine Art Container. Ein optionaler String ist ein Container, der möglicherweise einen String enthält. Ein optionales Int ist ein Container, der ein Int enthalten kann. Stellen Sie sich ein optionales Paket als eine Art Paket vor. Bevor Sie es öffnen (oder in der Sprache der Optionen "auspacken"), wissen Sie nicht, ob es etwas oder nichts enthält.

Sie können sehen, wie Optionen in der Swift-Standardbibliothek implementiert sind, indem Sie "Optional" in eine Swift-Datei eingeben und ⌘ darauf klicken. Hier ist der wichtige Teil der Definition:

enum Optional<Wrapped> {
    case none
    case some(Wrapped)
}

Optional ist nur enumeiner von zwei Fällen: .noneoder .some. Wenn ja .some, gibt es einen zugeordneten Wert, der im obigen Beispiel String"Hallo" wäre. Ein optionales Element verwendet Generics, um dem zugeordneten Wert einen Typ zuzuweisen. Der Typ eines optionalen String ist nicht String, es ist Optional, oder genauer gesagt Optional<String>.

Alles, was Swift mit Optionen macht, ist magisch, um das Lesen und Schreiben von Code flüssiger zu gestalten. Leider verdeckt dies die Art und Weise, wie es tatsächlich funktioniert. Ich werde später einige der Tricks durchgehen.

Hinweis: Ich werde viel über optionale Variablen sprechen, aber es ist auch in Ordnung, optionale Konstanten zu erstellen. Ich markiere alle Variablen mit ihrem Typ, um das Verständnis der erstellten Typtypen zu erleichtern, aber Sie müssen dies nicht in Ihrem eigenen Code tun.


So erstellen Sie Optionen

Um ein optionales Element zu erstellen, fügen Sie ?nach dem Typ, den Sie umbrechen möchten, ein an. Jeder Typ kann optional sein, auch Ihre eigenen benutzerdefinierten Typen. Sie können kein Leerzeichen zwischen dem Typ und dem haben ?.

var name: String? = "Bob" // Create an optional String that contains "Bob"
var peter: Person? = Person() // An optional "Person" (custom type)

// A class with a String and an optional String property
class Car {
var modelName: String // must exist
var internalName: String? // may or may not exist
}

Optionale Optionen verwenden

Sie können ein optionales Element vergleichen, nilum festzustellen, ob es einen Wert hat:

var name: String? = "Bob"
name = nil // Set name to nil, the absence of a value
if name != nil {
    print("There is a name")
}
if name == nil { // Could also use an "else"
    print("Name has no value")
}

Das ist etwas verwirrend. Dies impliziert, dass ein optionales Element entweder das eine oder das andere ist. Es ist entweder Null oder es ist "Bob". Dies ist nicht wahr, das Optionale verwandelt sich nicht in etwas anderes. Der Vergleich mit Null ist ein Trick, um den Code besser lesbar zu machen. Wenn eine Option gleich Null ist, bedeutet dies nur, dass die Aufzählung derzeit auf gesetzt ist .none.


Nur Optionen können Null sein

Wenn Sie versuchen, eine nicht optionale Variable auf Null zu setzen, wird eine Fehlermeldung angezeigt.

var red: String = "Red"
red = nil // error: nil cannot be assigned to type 'String'

Eine andere Sichtweise auf Optionen ist die Ergänzung zu normalen Swift-Variablen. Sie sind ein Gegenstück zu einer Variablen, deren Wert garantiert ist. Swift ist eine vorsichtige Sprache, die Mehrdeutigkeiten hasst. Die meisten Variablen werden als nicht optional definiert, aber manchmal ist dies nicht möglich. Stellen Sie sich beispielsweise einen View Controller vor, der ein Bild entweder aus einem Cache oder aus dem Netzwerk lädt. Möglicherweise ist dieses Bild zum Zeitpunkt der Erstellung des Ansichtscontrollers vorhanden oder nicht. Es gibt keine Möglichkeit, den Wert für die Bildvariable zu garantieren. In diesem Fall müssten Sie es optional machen. Es beginnt, nilwenn das Bild abgerufen wird und das optionale einen Wert erhält.

Die Verwendung einer Option zeigt die Absicht des Programmierers. Im Vergleich zu Objective-C, bei dem jedes Objekt Null sein könnte, muss Swift klar sein, wann ein Wert fehlen kann und wann er garantiert existiert.


Um ein optionales zu verwenden, "packen" Sie es aus

Ein optionales Stringkann nicht anstelle eines tatsächlichen verwendet werden String. Um den umschlossenen Wert in einem optionalen Wert zu verwenden, müssen Sie ihn auspacken. Der einfachste Weg, ein optionales Element zu entpacken, besteht darin, !nach dem optionalen Namen ein nachträgliches hinzuzufügen . Dies wird als "Force Unwrapping" bezeichnet. Es gibt den Wert innerhalb des optionalen (als ursprünglichen Typ) zurück, aber wenn das optionale ist nil, verursacht es einen Laufzeitabsturz. Vor dem Auspacken sollten Sie sicher sein, dass es einen Wert gibt.

var name: String? = "Bob"
let unwrappedName: String = name!
print("Unwrapped name: \(unwrappedName)")

name = nil
let nilName: String = name! // Runtime crash. Unexpected nil.

Überprüfen und Verwenden eines optionalen

Da Sie vor dem Auspacken und Verwenden eines optionalen Elements immer auf Null prüfen sollten, ist dies ein häufiges Muster:

var mealPreference: String? = "Vegetarian"
if mealPreference != nil {
    let unwrappedMealPreference: String = mealPreference!
    print("Meal: \(unwrappedMealPreference)") // or do something useful
}

In diesem Muster überprüfen Sie, ob ein Wert vorhanden ist. Wenn Sie sicher sind, dass dies der Fall ist, erzwingen Sie das Entpacken in eine temporäre Konstante. Da dies so häufig vorkommt, bietet Swift eine Verknüpfung mit "if let" an. Dies wird als "optionale Bindung" bezeichnet.

var mealPreference: String? = "Vegetarian"
if let unwrappedMealPreference: String = mealPreference {
    print("Meal: \(unwrappedMealPreference)") 
}

Dies erzeugt eine temporäre Konstante (oder eine Variable , wenn Sie ersetzen letmit var) , dessen Umfang ist nur innerhalb der , wenn die Klammern. Da die Verwendung eines Namens wie "unwrappedMealPreference" oder "realMealPreference" eine Belastung darstellt, können Sie mit Swift den ursprünglichen Variablennamen wiederverwenden und einen temporären Namen innerhalb des Klammerbereichs erstellen

var mealPreference: String? = "Vegetarian"
if let mealPreference: String = mealPreference {
    print("Meal: \(mealPreference)") // separate from the other mealPreference
}

Hier ist ein Code, der zeigt, dass eine andere Variable verwendet wird:

var mealPreference: String? = "Vegetarian"
if var mealPreference: String = mealPreference {
    print("Meal: \(mealPreference)") // mealPreference is a String, not a String?
    mealPreference = "Beef" // No effect on original
}
// This is the original mealPreference
print("Meal: \(mealPreference)") // Prints "Meal: Optional("Vegetarian")"

Die optionale Bindung überprüft, ob die Option gleich Null ist. Wenn dies nicht der Fall ist, wird das optionale Element in die angegebene Konstante entpackt und der Block ausgeführt. In Xcode 8.3 und höher (Swift 3.1) führt der Versuch, eine solche Option zu drucken, zu einer nutzlosen Warnung. Verwenden Sie die optionalen Optionen debugDescription, um es zum Schweigen zu bringen:

print("\(mealPreference.debugDescription)")

Wofür sind Optionen?

Optionale haben zwei Anwendungsfälle:

  1. Dinge, die scheitern können (ich hatte etwas erwartet, aber nichts bekommen)
  2. Dinge, die jetzt nichts sind, aber etwas später sein könnten (und umgekehrt)

Einige konkrete Beispiele:

  • Eine Eigenschaft, die dort sein kann oder nicht, wie middleNameoder spousein einer PersonKlasse
  • Eine Methode, die einen Wert oder nichts zurückgeben kann, z. B. die Suche nach einer Übereinstimmung in einem Array
  • Eine Methode, die entweder ein Ergebnis zurückgeben oder einen Fehler erhalten und nichts zurückgeben kann, z. B. den Versuch, den Inhalt einer Datei zu lesen (die normalerweise die Daten der Datei zurückgibt), aber die Datei existiert nicht
  • Delegieren Sie Eigenschaften, die nicht immer festgelegt werden müssen und in der Regel nach der Initialisierung festgelegt werden
  • Für weakEigenschaften in Klassen. Das, worauf sie zeigen, kann jederzeit eingestellt nilwerden
  • Eine große Ressource, die möglicherweise freigegeben werden muss, um Speicher zurückzugewinnen
  • Wenn Sie wissen möchten, wann ein Wert festgelegt wurde (Daten noch nicht geladen> die Daten), anstatt ein separates dataLoaded zu verwenden Boolean

In Objective-C gibt es keine Optionen, aber es gibt ein gleichwertiges Konzept, das null zurückgibt. Methoden, die ein Objekt zurückgeben können, können stattdessen nil zurückgeben. Dies bedeutet "das Fehlen eines gültigen Objekts" und wird oft verwendet, um zu sagen, dass etwas schief gelaufen ist. Es funktioniert nur mit Objective-C-Objekten, nicht mit Grundelementen oder grundlegenden C-Typen (Aufzählungen, Strukturen). Objective-C hatte häufig spezielle Typen, um das Fehlen dieser Werte darzustellen ( NSNotFoundwas wirklich bedeutet NSIntegerMax, kCLLocationCoordinate2DInvalideine ungültige Koordinate darzustellen, -1oder es werden auch einige negative Werte verwendet). Der Codierer muss diese speziellen Werte kennen, damit sie für jeden Fall dokumentiert und gelernt werden müssen. Wenn eine Methode nicht nilals Parameter verwendet werden kann, muss dies dokumentiert werden. In Objective-Cnilwar ein Zeiger, genau wie alle Objekte als Zeiger definiert wurden, aber nilauf eine bestimmte (Null-) Adresse zeigten. In Swift nilist ein Literal, was das Fehlen eines bestimmten Typs bedeutet.


Verglichen mit nil

Früher konnten Sie alle optionalen Optionen verwenden als Boolean:

let leatherTrim: CarExtras? = nil
if leatherTrim {
    price = price + 1000
}

In neueren Versionen von Swift müssen Sie verwenden leatherTrim != nil. Warum ist das? Das Problem ist, dass a Booleanin ein optionales eingewickelt werden kann. Wenn Ihnen das Booleangefällt:

var ambiguous: Boolean? = false

Es gibt zwei Arten von "falsch", eine, bei der es keinen Wert gibt, und eine, bei der es einen Wert hat, aber der Wert ist false. Swift hasst Mehrdeutigkeiten, daher müssen Sie jetzt immer eine Option gegen prüfen nil.

Sie fragen sich vielleicht, wozu ein optionales Element gut Booleanist? Wie bei anderen Optionen könnte der .noneStatus anzeigen, dass der Wert noch unbekannt ist. Möglicherweise befindet sich am anderen Ende eines Netzwerkanrufs etwas, dessen Abfrage einige Zeit in Anspruch nimmt. Optionale Boolesche Werte werden auch als " Drei-Wert-Boolesche Werte " bezeichnet.


Schnelle Tricks

Swift verwendet einige Tricks, damit Optionen funktionieren. Betrachten Sie diese drei Zeilen mit normal aussehendem optionalem Code.

var religiousAffiliation: String? = "Rastafarian"
religiousAffiliation = nil
if religiousAffiliation != nil { ... }

Keine dieser Zeilen sollte kompiliert werden.

  • In der ersten Zeile wird ein optionaler String mit einem String-Literal festgelegt, zwei verschiedenen Typen. Auch wenn dies ein war, sind Stringdie Typen unterschiedlich
  • In der zweiten Zeile wird ein optionaler String auf null gesetzt, zwei verschiedene Typen
  • Die dritte Zeile vergleicht eine optionale Zeichenfolge mit null, zwei verschiedenen Typen

Ich werde einige Implementierungsdetails von Optionen durchgehen, mit denen diese Zeilen funktionieren.


Optional erstellen

Mit ?einem optionalen erstellen ist syntaktischer Zucker, durch den Compiler Swift aktiviert. Wenn Sie es auf lange Sicht tun möchten, können Sie eine Option wie die folgende erstellen:

var name: Optional<String> = Optional("Bob")

Dies ruft Optionalden ersten Initialisierer auf, public init(_ some: Wrapped)der den zugehörigen Typ des optionalen Typs von dem in den Klammern verwendeten Typ ableitet.

Die noch längere Möglichkeit, eine Option zu erstellen und festzulegen:

var serialNumber:String? = Optional.none
serialNumber = Optional.some("1234")
print("\(serialNumber.debugDescription)")

Optionale Einstellung auf nil

Sie können eine Option ohne Anfangswert oder eine Option mit dem Anfangswert von erstellen nil(beide haben das gleiche Ergebnis).

var name: String?
var name: String? = nil

Das Zulassen, dass Optionen gleich sind, nilwird durch das Protokoll ExpressibleByNilLiteral(zuvor benannt NilLiteralConvertible) aktiviert . Das optionale wird mit Optionaldem zweiten Initialisierer erstellt public init(nilLiteral: ()). Die Dokumente sagen, dass Sie ExpressibleByNilLiteralnichts anderes als Optionen verwenden sollten, da dies die Bedeutung von Null in Ihrem Code ändern würde, aber es ist möglich, dies zu tun:

class Clint: ExpressibleByNilLiteral {
    var name: String?
    required init(nilLiteral: ()) {
        name = "The Man with No Name"
    }
}

let clint: Clint = nil // Would normally give an error
print("\(clint.name)")

Mit demselben Protokoll können Sie eine bereits erstellte Option auf festlegen nil. Obwohl dies nicht empfohlen wird, können Sie den Null-Literal-Initialisierer direkt verwenden:

var name: Optional<String> = Optional(nilLiteral: ())

Vergleich eines optionalen mit nil

Optionals definieren zwei spezielle "==" - und "! =" - Operatoren, die Sie in der OptionalDefinition sehen können. Mit der ersten ==Option können Sie überprüfen, ob eine Option gleich Null ist. Zwei verschiedene Optionen, die auf .none gesetzt sind, sind immer gleich, wenn die zugehörigen Typen gleich sind. Wenn Sie mit nil vergleichen, erstellt Swift hinter den Kulissen eine Option desselben zugeordneten Typs, die auf .none gesetzt ist, und verwendet diese dann für den Vergleich.

// How Swift actually compares to nil
var tuxedoRequired: String? = nil
let temp: Optional<String> = Optional.none
if tuxedoRequired == temp { // equivalent to if tuxedoRequired == nil
    print("tuxedoRequired is nil")
}

Mit dem zweiten ==Operator können Sie zwei Optionen vergleichen. Beide müssen vom selben Typ sein und dieser Typ muss übereinstimmen Equatable(das Protokoll, mit dem Dinge mit dem regulären Operator "==" verglichen werden können). Swift packt (vermutlich) die beiden Werte aus und vergleicht sie direkt. Es behandelt auch den Fall, in dem eine oder beide Optionen verfügbar sind .none. Beachten Sie den Unterschied zwischen dem Vergleich mit dem nilLiteral.

Darüber hinaus können Sie jeden EquatableTyp mit einem optionalen Wrapping dieses Typs vergleichen:

let numberToFind: Int = 23
let numberFromString: Int? = Int("23") // Optional(23)
if numberToFind == numberFromString {
    print("It's a match!") // Prints "It's a match!"
}

Hinter den Kulissen verpackt Swift das Nicht-Optionale vor dem Vergleich als Optional. Es funktioniert auch mit Literalen ( if 23 == numberFromString {)

Ich sagte, es gibt zwei ==Operatoren, aber es gibt tatsächlich einen dritten, mit dem Sie nildie linke Seite des Vergleichs angeben können

if nil == name { ... }

Optionale benennen

Es gibt keine Swift-Konvention, um optionale Typen anders als nicht optionale Typen zu benennen. Die Leute vermeiden es, dem Namen etwas hinzuzufügen, um anzuzeigen, dass es sich um einen optionalen Typ handelt (z. B. "optionalMiddleName" oder "möglicherNumberAsString"), und lassen die Deklaration anzeigen, dass es sich um einen optionalen Typ handelt. Dies wird schwierig, wenn Sie etwas benennen möchten, das den Wert von einem optionalen Wert enthält. Der Name "middleName" impliziert, dass es sich um einen String-Typ handelt. Wenn Sie also den String-Wert daraus extrahieren, erhalten Sie häufig Namen wie "actualMiddleName" oder "unwrappedMiddleName" oder "realMiddleName". Verwenden Sie die optionale Bindung und verwenden Sie den Variablennamen erneut, um dies zu umgehen.


Die offizielle Definition

Aus "The Basics" in der Swift-Programmiersprache :

Swift führt auch optionale Typen ein, die das Fehlen eines Werts behandeln. Optionale Optionen sagen entweder "es gibt einen Wert und er ist gleich x" oder "es gibt überhaupt keinen Wert". Optionals ähneln der Verwendung von nil mit Zeigern in Objective-C, funktionieren jedoch für jeden Typ, nicht nur für Klassen. Optionals sind sicherer und aussagekräftiger als Nullzeiger in Objective-C und bilden das Herzstück vieler der leistungsstärksten Funktionen von Swift.

Optionals sind ein Beispiel für die Tatsache, dass Swift eine typsichere Sprache ist. Swift hilft Ihnen dabei, klar zu machen, mit welchen Arten von Werten Ihr Code arbeiten kann. Wenn ein Teil Ihres Codes einen String erwartet, verhindert die Typensicherheit, dass Sie ihm versehentlich ein Int übergeben. Auf diese Weise können Sie Fehler so früh wie möglich im Entwicklungsprozess erkennen und beheben.


Zum Abschluss hier ein Gedicht aus dem Jahr 1899 über Optionen:

Gestern auf der Treppe
traf ich einen Mann, der nicht da war.
Er war heute nicht wieder da.
Ich wünschte, er würde
Antigonish weggehen


Mehr Ressourcen:


5
@ KaanDedeoglu Leider ist Steve sehr optional. Er war hier und jetzt ist er nicht.
Nevan König

19
if myStringkompiliert nicht mehr. Du brauchst if myString != nil. Siehe Dokumentation .
Pang

5
beste und klarste Erklärung für? und ! Verwendung in Swift fand ich im Web. danke
mindbomb

2
mateo erklärt ausführlich die Optionals und geht eingehend auf einfache Beispiele ein.
iluvatar_GR

4
Vielen Dank für diese Erklärung, sie ist viel klarer als Apples eigene Dokumentation.
Yesthisisjoe

16

Nehmen wir das Beispiel eines NSError: Wenn kein Fehler zurückgegeben wird, möchten Sie es optional machen, Nil zurückzugeben. Es macht keinen Sinn, ihm einen Wert zuzuweisen, wenn kein Fehler vorliegt.

var error: NSError? = nil

Auf diese Weise können Sie auch einen Standardwert festlegen. Sie können einer Methode also einen Standardwert festlegen, wenn der Funktion nichts übergeben wird

func doesntEnterNumber(x: Int? = 5) -> Bool {
    if (x == 5){
        return true
    } else {
        return false
    }
}

Der Satz "Wenn es Null ist, ist das Ergebnis eines Ausdrucks auch Null" ist einfach falsch. func isNil<T>(t: T?) -> Bool { return t == nil }wird zurückgegeben, trueauch wenn nilder Ausdruck einen optionalen Wert enthält .
Rückgabe wahr

Unglaublich schlechtes Codebeispiel. Könnten Sie sich nichts Besseres vorstellen? Warum nicht einfach return x == 5? Was ist das Besondere an 5?
Atomosk

Nein, vor 2 Jahren konnte ich mir nichts Besseres vorstellen. Heute ja, aber bringt das den Punkt rüber? Ja. Vielen Dank für die Eingabe @Atomosk, es ist wirklich hilfreich.
John Riselvato

12

Sie können nilin Swift keine Variable haben, auf die verweist - es gibt keine Zeiger und keine Nullzeiger. In einer API möchten Sie jedoch häufig entweder eine bestimmte Art von Wert oder einen Wertmangel angeben können - z. B. hat mein Fenster einen Delegaten, und wenn ja, wer ist das? Optionals sind Swifts typsichere und speichersichere Methode, um dies zu tun.


11

Ich gab eine kurze Antwort, die die meisten der oben genannten Punkte zusammenfasst, um die Unsicherheit zu beseitigen, die ich als Anfänger in meinem Kopf hatte:

Im Gegensatz zu Objective-C kann keine Variable in Swift Null enthalten , daher wurde der optionale Variablentyp hinzugefügt (Variablen mit dem Suffix "?"):

    var aString = nil //error

Der große Unterschied besteht darin, dass die optionalen Variablen keine Werte direkt speichern (wie es normale Obj-C-Variablen tun würden). Sie enthalten zwei Zustände : " hat einen Wert " oder " hat null ":

    var aString: String? = "Hello, World!"
    aString = nil //correct, now it contains the state "has nil"

In diesem Fall können Sie diese Variablen in verschiedenen Situationen überprüfen:

if let myString = aString? {
     println(myString)
}
else { 
     println("It's nil") // this will print in our case
}

Mit dem "!" Mit dem Suffix können Sie auch nur dann auf die darin eingeschlossenen Werte zugreifen, wenn diese vorhanden sind . (dh es ist nicht Null ):

let aString: String? = "Hello, World!"
// var anotherString: String = aString //error
var anotherString: String = aString!

println(anotherString) //it will print "Hello, World!"

Deshalb müssen Sie "?" und "!" und verwenden Sie nicht alle standardmäßig. (Dies war meine größte Verwirrung)

Ich stimme auch der obigen Antwort zu: Der optionale Typ kann nicht als Boolescher Wert verwendet werden .


7

In Ziel C waren Variablen ohne Wert gleich 'nil' (es war auch möglich, 'nil'-Werte wie 0 und false zu verwenden), daher war es möglich, Variablen in bedingten Anweisungen zu verwenden (Variablen mit Werten sind gleich' TRUE ' 'und diejenigen ohne Werte waren gleich' FALSE ').

Swift bietet Typensicherheit durch Bereitstellung eines optionalen Werts. Das heißt, es verhindert, dass Fehler entstehen, die Variablen unterschiedlichen Typs zuweisen.

In Swift können also nur Boolesche Werte für bedingte Anweisungen angegeben werden.

var hw = "Hello World"

Obwohl 'hw' eine Zeichenfolge ist, kann sie hier nicht in einer if-Anweisung wie in Ziel C verwendet werden.

//This is an error

if hw

 {..}

Dafür muss es erstellt werden als,

var nhw : String? = "Hello World"

//This is correct

if nhw

 {..}

5

Mit dem optionalen Wert können Sie das Fehlen eines Werts anzeigen. Ein bisschen wie NULL in SQL oder NSNull in Objective-C. Ich denke, dies wird eine Verbesserung sein, da Sie dies sogar für "primitive" Typen verwenden können.

// Reimplement the Swift standard library's optional type
enum OptionalValue<T> {
    case None
    case Some(T)
}
var possibleInteger: OptionalValue<Int> = .None
possibleInteger = .Some(100)

Auszug aus: Apple Inc. "Die schnelle Programmiersprache". iBooks. https://itun.es/gb/jEUH0.l


6
nilist nur syntaktischer Zucker für die Enum-Konstante OptionalValue<T>.None(wobei Tder Typ dem Kontext entspricht, in dem Sie ihn verwenden nil). ?ist eine Abkürzung für OptionalValue<T>.Some(T).
Rickster

4

Ein optionales Mittel bedeutet, dass Swift nicht ganz sicher ist, ob der Wert dem Typ entspricht: Zum Beispiel Int? bedeutet, dass Swift nicht ganz sicher ist, ob die Nummer ein Int ist.

Um es zu entfernen, gibt es drei Methoden, die Sie anwenden können.

1) Wenn Sie sich des Typs absolut sicher sind, können Sie ein Ausrufezeichen verwenden, um das Auspacken wie folgt zu erzwingen:

// Here is an optional variable:

var age: Int?

// Here is how you would force unwrap it:

var unwrappedAge = age!

Wenn Sie ein optionales Entpacken erzwingen und es gleich Null ist, kann dieser Absturzfehler auftreten:

Geben Sie hier die Bildbeschreibung ein

Dies ist nicht unbedingt sicher. Hier ist eine Methode, die einen Absturz verhindern kann, falls Sie sich über Typ und Wert nicht sicher sind:

Die Methoden 2 und 3 schützen vor diesem Problem.

2) Die implizit ausgepackte Option

 if let unwrappedAge = age {

 // continue in here

 }

Beachten Sie, dass der entpackte Typ jetzt Int ist und nicht Int? .

3) Die Wachaussage

 guard let unwrappedAge = age else { 
   // continue in here
 }

Von hier aus können Sie die entpackte Variable verwenden. Stellen Sie sicher, dass Sie das Auspacken nur erzwingen (mit einem!), Wenn Sie sich über den Typ der Variablen sicher sind.

Viel Glück bei Ihrem Projekt!


1

Als ich anfing zu lernen Swift, war es sehr schwierig zu verstehen, warum optional .

Denken wir so. Betrachten wir eine Klasse Personmit zwei Eigenschaften nameund company.

class Person: NSObject {

    var name : String //Person must have a value so its no marked as optional
    var companyName : String? ///Company is optional as a person can be unemployed that is nil value is possible

    init(name:String,company:String?) {

        self.name = name
        self.companyName = company

    }
}

Lassen Sie uns nun einige Objekte von erstellen Person

var tom:Person = Person.init(name: "Tom", company: "Apple")//posible
var bob:Person = Person.init(name: "Bob", company:nil) // also Possible because company is marked as optional so we can give Nil

Aber wir können nicht passieren Nilzuname

var personWithNoName:Person = Person.init(name: nil, company: nil)

Sprechen wir jetzt darüber, warum wir verwenden optional?. Betrachten wir eine Situation, in der wir Incnach dem Firmennamen hinzufügen möchten, wie applees sein wird apple Inc. Wir müssen Incnach Firmennamen anhängen und drucken.

print(tom.companyName+" Inc") ///Error saying optional is not unwrapped.
print(tom.companyName!+" Inc") ///Error Gone..we have forcefully unwrap it which is wrong approach..Will look in Next line
print(bob.companyName!+" Inc") ///Crash!!!because bob has no company and nil can be unwrapped.

Lassen Sie uns nun untersuchen, warum optional erfolgt.

if let companyString:String = bob.companyName{///Compiler safely unwrap company if not nil.If nil,no unwrap.

    print(companyString+" Inc") //Will never executed and no crash!!!
}

Lässt ersetzen bobmittom

if let companyString:String = tom.companyName{///Compiler safely unwrap company if not nil.If nil,no unwrap.

    print(companyString+" Inc") //Will never executed and no crash!!!
}

Und herzlichen Glückwunsch! wir haben richtig damit umgegangenoptional?

Die Realisierungspunkte sind also

  1. Wir werden eine Variable als optional markieren, wenn dies möglich ist nil
  2. Wenn wir diese Variable irgendwo im Code-Compiler verwenden möchten, werden Sie daran erinnert, dass wir prüfen müssen, ob wir mit dieser Variablen richtig umgehen können, wenn sie enthält nil.

Vielen Dank ... Happy Coding


0

Experimentieren wir mit dem unten stehenden Code Playground. Ich hoffe, dass die Idee klar ist, was optional ist und warum sie verwendet wird.

var sampleString: String? ///Optional, Possible to be nil

sampleString = nil ////perfactly valid as its optional

sampleString = "some value"  //Will hold the value

if let value = sampleString{ /// the sampleString is placed into value with auto force upwraped.

    print(value+value)  ////Sample String merged into Two
}

sampleString = nil // value is nil and the

if let value = sampleString{

    print(value + value)  ///Will Not execute and safe for nil checking
}

//   print(sampleString! + sampleString!)  //this line Will crash as + operator can not add nil

0

Von https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/OptionalChaining.html :

Die optionale Verkettung ist ein Prozess zum Abfragen und Aufrufen von Eigenschaften, Methoden und Indizes für eine Option, die derzeit möglicherweise Null ist. Wenn das optionale Element einen Wert enthält, ist der Aufruf der Eigenschaft, Methode oder des Index erfolgreich. Wenn das optionale Element nil ist, gibt der Eigenschafts-, Methoden- oder Indexaufruf nil zurück. Es können mehrere Abfragen miteinander verkettet werden, und die gesamte Kette schlägt ordnungsgemäß fehl, wenn ein Glied in der Kette Null ist.

Um tiefer zu verstehen, lesen Sie den obigen Link.


0

Gut...

? (Optional) gibt an, dass Ihre Variable möglicherweise einen Nullwert enthält, während ! (Unwrapper) gibt an, dass Ihre Variable einen Speicher (oder Wert) haben muss, wenn sie zur Laufzeit verwendet wird (versucht wird, einen Wert daraus abzurufen).

Der Hauptunterschied besteht darin, dass die optionale Verkettung ordnungsgemäß fehlschlägt, wenn die optionale Option Null ist, während das erzwungene Entpacken einen Laufzeitfehler auslöst, wenn die optionale Option Null ist.

Um die Tatsache widerzuspiegeln, dass optionale Verkettung für einen Nullwert aufgerufen werden kann, ist das Ergebnis eines optionalen Verkettungsaufrufs immer ein optionaler Wert, selbst wenn die Eigenschaft, Methode oder der Index, den Sie abfragen, einen nicht optionalen Wert zurückgibt. Mit diesem optionalen Rückgabewert können Sie überprüfen, ob der optionale Verkettungsaufruf erfolgreich war (das zurückgegebene optionale enthält einen Wert) oder aufgrund eines Nullwerts in der Kette nicht erfolgreich war (der zurückgegebene optionale Wert ist null).

Insbesondere ist das Ergebnis eines optionalen Verkettungsaufrufs vom gleichen Typ wie der erwartete Rückgabewert, jedoch in einen optionalen Wert eingeschlossen. Eine Eigenschaft, die normalerweise ein Int zurückgibt, gibt ein Int? beim Zugriff durch optionale Verkettung.

var defaultNil : Int?  // declared variable with default nil value
println(defaultNil) >> nil  

var canBeNil : Int? = 4
println(canBeNil) >> optional(4)

canBeNil = nil
println(canBeNil) >> nil

println(canBeNil!) >> // Here nil optional variable is being unwrapped using ! mark (symbol), that will show runtime error. Because a nil optional is being tried to get value using unwrapper

var canNotBeNil : Int! = 4
print(canNotBeNil) >> 4

var cantBeNil : Int = 4
cantBeNil = nil // can't do this as it's not optional and show a compile time error

Hier finden Sie ein detailliertes Tutorial des Apple Developer Committee: Optionale Verkettung



-1

Hier ist eine äquivalente optionale Deklaration in Swift:

var middleName: String?

Diese Deklaration erstellt eine Variable mit dem Namen middleName vom Typ String. Das Fragezeichen (?) Nach dem Variablentyp "String" gibt an, dass die Variable "middleName" einen Wert enthalten kann, der entweder "String" oder "Null" sein kann. Jeder, der sich diesen Code ansieht, weiß sofort, dass MiddleName Null sein kann. Es ist selbstdokumentierend!

Wenn Sie keinen Anfangswert für eine optionale Konstante oder Variable angeben (wie oben gezeigt), wird der Wert für Sie automatisch auf Null gesetzt. Wenn Sie möchten, können Sie den Anfangswert explizit auf Null setzen:

var middleName: String? = nil

Weitere Informationen zum optionalen Link finden Sie unter dem folgenden Link

http://www.iphonelife.com/blog/31369/swift-101-working-swifts-new-optional-values


benutze dies, var middleName: String! = ""
Gaurav
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.