wake-up-neo.net

Was ist ein "ungeöffneter Wert" in Swift?

Ich lerne Swift für iOS 8/OSX 10.10 durch Befolgen von dieses Tutorial und dem Begriff " ungeöffneter Wert "wird mehrmals verwendet, wie in diesem Absatz (unter Objekte und Klasse):

Wenn Sie mit optionalen Werten arbeiten, können Sie schreiben? vor Operationen wie Methoden, Eigenschaften und Subskription. Wenn der Wert vor dem? ist nichts, alles nach dem? wird ignoriert und der Wert des gesamten Ausdrucks ist Null. Andernfalls wird der optionale Wert entpackt und alles nach dem? Wirkt auf den unverpackten Wert . In beiden Fällen ist der Wert des gesamten Ausdrucks ein optionaler Wert.

let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square") 
let sideLength = optionalSquare?.sideLength

Ich verstehe es nicht und habe ohne Glück im Internet gesucht.

Was bedeutet das?


Bearbeiten

Aus Cezarys Antwort geht hervor, dass es einen kleinen Unterschied zwischen der Ausgabe des Originalcodes und der endgültigen Lösung gibt (getestet auf dem Spielplatz):

Originalcode

Original code

Cezarys Lösung

Cezary's solution

Die Eigenschaften der Oberklasse werden in der Ausgabe im zweiten Fall angezeigt, während im ersten Fall ein leeres Objekt vorhanden ist.

Sollte das Ergebnis nicht in beiden Fällen identisch sein?

Verwandte Fragen und Antworten: Was ist ein optionaler Wert in Swift?

154
Bigood

Zunächst müssen Sie verstehen, was ein optionaler Typ ist. Ein optionaler Typ bedeutet grundsätzlich, dass die Variable nil sein kann.

Beispiel:

var canBeNil : Int? = 4
canBeNil = nil

Das Fragezeichen zeigt an, dass canBeNilnil sein kann.

Das würde nicht funktionieren:

var cantBeNil : Int = 4
cantBeNil = nil // can't do this

Um den Wert aus Ihrer Variablen zu erhalten, müssen Sie auspacken . Dies bedeutet nur, ein Ausrufezeichen am Ende zu setzen.

var canBeNil : Int? = 4
println(canBeNil!)

Ihr Code sollte folgendermaßen aussehen:

let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square") 
let sideLength = optionalSquare!.sideLength

Eine Randnotiz:

Sie können auch festlegen, dass Optionsfelder automatisch ausgepackt werden, indem Sie anstelle eines Fragezeichens ein Ausrufezeichen verwenden.

Beispiel:

var canBeNil : Int! = 4
print(canBeNil) // no unwrapping needed

Eine alternative Möglichkeit, Ihren Code zu reparieren, ist:

let optionalSquare: Square! = Square(sideLength: 2.5, name: "optional square") 
let sideLength = optionalSquare.sideLength

BEARBEITEN:

Der Unterschied, den Sie sehen, ist genau das Symptom dafür, dass der optionale Wert umbrochen ist. Darauf befindet sich eine weitere Schicht. Die Version ausgepackt zeigt nur das gerade Objekt, weil es gut ausgepackt ist.

Ein kurzer Spielplatzvergleich:

playground

Im ersten und zweiten Fall wird das Objekt nicht automatisch entpackt, sodass zwei "Ebenen" ({{...}}), während Sie im dritten Fall nur eine Ebene sehen ({...}) weil das Objekt automatisch entpackt wird.

Der Unterschied zwischen dem ersten und den beiden zweiten Fällen besteht darin, dass die beiden zweiten Fälle einen Laufzeitfehler verursachen, wenn optionalSquare auf nil gesetzt ist. Wenn Sie im ersten Fall die Syntax verwenden, können Sie Folgendes tun:

if let sideLength = optionalSquare?.sideLength {
    println("sideLength is not nil")
} else {
    println("sidelength is nil")
}
285
Cezary Wojcik

Die existierende richtige Antwort ist großartig, aber ich fand, dass ich eine gute Analogie brauchte, um dies vollständig zu verstehen, da dies ein sehr abstraktes und seltsames Konzept ist.

Lassen Sie mich den anderen Entwicklern helfen, die mit dem richtigen Blickwinkel (visuelles Denken) zu tun haben, indem Sie zusätzlich zur richtigen Antwort eine andere Perspektive angeben. Hier ist eine gute Analogie, die mir sehr geholfen hat.

Geburtstagsgeschenk Wickelanalogie

Stellen Sie sich Optionals wie Geburtstagsgeschenke vor, die in einer steifen, harten, farbigen Verpackung geliefert werden.

Sie wissen nicht, ob etwas in der Verpackung ist, bis Sie das Geschenk auspacken - vielleicht ist gar nichts drin! Wenn etwas drin ist, könnte es sich um ein weiteres Geschenk handeln, das ebenfalls verpackt ist und das auch möglicherweise nichts enthält. Sie könnten sogar 100 verschachtelte Geschenke auspacken, um endlich zu entdecken, dass es nichts als Verpackung gab.

Wenn der Wert des optionalen nicht nil ist, haben Sie jetzt eine Box mit etwas aufgedeckt. Aber vor allem, wenn der Wert nicht explizit eingegeben wurde und eine Variable und keine vordefinierte Konstante ist, müssen Sie möglicherweise noch das Kästchen öffnen, bevor Sie etwas Spezifisches über den Inhalt des Kästchens erfahren können. wie welcher Typ es ist, oder was der tatsächliche Wert ist.

Was ist in der Box? ! Analogie

Auch nachdem Sie die Variable ausgepackt haben, sind Sie immer noch wie Brad Pitt in der letzten Szene in SE7EN ( Warnung: Spoiler und sehr R-bewertete Schimpfwörter und Gewalt), Denn auch nachdem Sie das Geschenk ausgepackt haben, befinden Sie sich in der folgenden Situation: Sie haben jetzt nil oder eine Schachtel mit etwas ( aber du weißt nicht was).

Sie kennen vielleicht den Typ des etwas. Wenn Sie beispielsweise die Variable als Typ deklariert haben, wird [Int:Any?], dann wüssten Sie, dass Sie ein (möglicherweise leeres) Wörterbuch mit Ganzzahl-Subskripten hatten, das umbrochenen Inhalt eines beliebigen alten Typs liefert.

Aus diesem Grund kann der Umgang mit Auflistungstypen (Wörterbücher und Arrays) in Swift) etwas haarig werden.

Ein typisches Beispiel:

typealias presentType = [Int:Any?]

func wrap(i:Int, gift:Any?) -> presentType? {
    if(i != 0) {
        let box : presentType = [i:wrap(i-1,gift:gift)]
        return box
    }
    else {
        let box = [i:gift]
        return box
    }
}

func getGift() -> String? {
    return "foobar"
}

let f00 = wrap(10,gift:getGift())

//Now we have to unwrap f00, unwrap its entry, then force cast it into the type we hope it is, and then repeat this in nested fashion until we get to the final value.

var b4r = (((((((((((f00![10]! as! [Int:Any?])[9]! as! [Int:Any?])[8]! as! [Int:Any?])[7]! as! [Int:Any?])[6]! as! [Int:Any?])[5]! as! [Int:Any?])[4]! as! [Int:Any?])[3]! as! [Int:Any?])[2]! as! [Int:Any?])[1]! as! [Int:Any?])[0])

//Now we have to DOUBLE UNWRAP the final value (because, remember, getGift returns an optional) AND force cast it to the type we hope it is

let asdf : String = b4r!! as! String

print(asdf)
17
CommaToast

Swift legt großen Wert auf Typensicherheit. Die gesamte Swift Sprache wurde mit Blick auf die Sicherheit entwickelt. Sie ist eines der Kennzeichen von Swift und eines, das Sie mit offenen Armen willkommen heißen sollten. Es wird helfen bei der Entwicklung von sauberem, lesbarem Code und verhindern, dass Ihre Anwendung abstürzt.

Alle Optionen in Swift sind mit dem Symbol ? gekennzeichnet. Wenn Sie das Symbol ? nach dem Namen des Typs setzen, in dem Sie als optional deklarieren, sind Sie im Wesentlichen casting Dies ist nicht der Typ, der vor dem ? steht, sondern der Typ optional.


Hinweis: Eine Variable oder ein Typ Int ist nicht dasselbe wie Int?. Es sind zwei verschiedene Typen, die nicht aneinander betrieben werden können.


Mit Optional

var myString: String?

myString = "foobar"

Dies bedeutet nicht, dass Sie mit einer Art String arbeiten. Dies bedeutet, dass Sie mit einem Typ von String? (String Optional oder Optional String) arbeiten. In der Tat, wann immer Sie versuchen

print(myString)

zur Laufzeit gibt die Debug-Konsole Optional("foobar") aus. Der Teil "Optional()" gibt an, dass diese Variable zur Laufzeit einen Wert haben kann oder nicht, aber gerade den String "foobar" enthält. Diese "Optional()" -Anzeige bleibt erhalten, sofern Sie nicht den optionalen Wert "auspacken".

nwrapping Optional bedeutet, dass Sie diesen Typ jetzt als nicht optional umwandeln. Dadurch wird ein neuer Typ generiert und der Wert, der sich in diesem optionalen Typ befand, dem neuen nicht optionalen Typ zugewiesen. Auf diese Weise können Sie Operationen für diese Variable ausführen, da der Compiler garantiert hat, dass sie einen soliden Wert hat.


Bedingt auspacken prüft, ob der Wert in der Option nil ist oder nicht. Wenn es nicht nil ist, wird eine neu erstellte Konstantenvariable erstellt, die den Wert und Unwrapped in die nicht-optionale Konstante einfügt. Und von dort aus können Sie das nicht-optionale Element sicher im Block if verwenden.

Hinweis: Sie können Ihrer bedingt entpackten Konstante denselben Namen geben wie der optionalen Variablen, die Sie entpacken.

if let myString = myString {
    print(myString)
    // will print "foobar"
}

Das bedingte Auspacken von Optionen ist die sauberste Methode, um auf den Wert einer Option zuzugreifen, da dann, wenn sie einen Nullwert enthält, alles im if let-Block nicht ausgeführt wird. Natürlich können Sie wie bei jeder if-Anweisung auch einen else-Block einfügen

if let myString = myString {
    print(myString)
    // will print "foobar"
}
else {
    print("No value")
}

Forcibly Unwrapping wird mit dem so genannten Operator ! ("bang") ausgeführt. Dies ist weniger sicher, ermöglicht jedoch die Kompilierung Ihres Codes. Wenn Sie jedoch den Bang-Operator verwenden, müssen Sie zu 1000% sicher sein, dass Ihre Variable tatsächlich einen festen Wert enthält, bevor Sie das gewaltsame Entpacken durchführen.

var myString: String?

myString = "foobar"

print(myString!)

Dies ist der vollständig gültige Code Swift. Er gibt den Wert von myString aus, der als "foobar" festgelegt wurde. Der Benutzer würde foobar gedruckt sehen in der Konsole und das war's auch schon. Aber nehmen wir an, der Wert wurde nie gesetzt:

var myString: String?

print(myString!) 

Jetzt haben wir eine andere Situation vor uns. Im Gegensatz zu Objective-C stürzt jedes Mal ab, wenn versucht wird, ein optionales Objekt gewaltsam zu entpacken, und wenn das optionale Objekt nicht festgelegt wurde und nil ist, wenn Sie versuchen, das optionale Objekt zu entpacken, um zu sehen, was in Ihrer Anwendung enthalten ist.


Auspacken mit Type Casting. Wie bereits erwähnt, können Sie, während Sie unwrapping das optionale Element sind, das Sie tatsächlich in einen nicht optionalen Typ umwandeln, das nicht optionale Element auch in einen anderen Typ umwandeln. Zum Beispiel:

var something: Any?

Irgendwo in unserem Code wird die Variable something mit einem Wert gesetzt. Vielleicht verwenden wir Generika oder vielleicht gibt es eine andere Logik, die dies ändern wird. Daher möchten wir später in unserem Code something verwenden, können es aber trotzdem anders behandeln, wenn es sich um einen anderen Typ handelt. In diesem Fall sollten Sie das Schlüsselwort as verwenden, um Folgendes zu ermitteln:

Hinweis: Mit dem Operator as geben Sie cast in Swift ein.

// Conditionally
if let thing = something as? Int {
    print(thing) // 0
}

// Optionally
let thing = something as? Int
print(thing) // Optional(0)

// Forcibly
let thing = something as! Int
print(thing) // 0, if no exception is raised

Beachten Sie den Unterschied zwischen den beiden Schlüsselwörtern as. Wie zuvor, als wir ein optionales Element gewaltsam ausgepackt haben, haben wir dazu den Bang-Operator ! verwendet. Hier machst du dasselbe, aber anstatt es nur als nicht optional zu gießen, wirfst du es auch als Int. Und es muss in der Lage sein, als Int niedergeschlagen zu werden, andernfalls stürzt Ihre Anwendung ab, wenn der Wert nil ist.

Und um diese Variablen überhaupt in irgendeiner Art oder mathematischen Operation zu verwenden, müssen sie dafür entpackt werden.

Zum Beispiel dürfen in Swift nur gültige Zahlendatentypen der gleichen Art aufeinander angewendet werden. Wenn Sie einen Typ mit dem as! umwandeln, erzwingen Sie den Downcast dieser Variablen als ob Sie sicher es ist von diesem Typ, daher sicher zu bedienen und Ihre Anwendung nicht zum Absturz zu bringen. Dies ist in Ordnung, solange die Variable tatsächlich von dem Typ ist, auf den Sie sie umwandeln. Andernfalls haben Sie ein Durcheinander in Ihren Händen.

Durch das Casting mit as! kann Ihr Code dennoch kompiliert werden. Beim Casting mit einem as? sieht die Geschichte anders aus. Tatsächlich deklariert as? Ihren Int als einen völlig anderen Datentyp.

Jetzt ist es Optional(0)

Und wenn Sie jemals versucht haben, Ihre Hausaufgaben zu machen, schreiben Sie so etwas wie

1 + Optional(1) = 2

Ihr Mathematiklehrer hätte Ihnen wahrscheinlich ein "F" gegeben. Dasselbe gilt für Swift. Außer Swift würde lieber gar nicht kompilieren, als dir eine Note zu geben. Weil am Ende des Tages die Option in der Tat Null sein kann.

Sicherheit geht vor Kinder.

13
Brandon A

'?' bedeutet optional Verkettungsausdruck

Das '!' bedeutet Force-Wert
enter image description here

0
gkgy