Optionale Variable drucken

118

Ich versuche es mit diesen Codezeilen

class Student {
    var name: String
    var age: Int?

    init(name: String) {
        self.name = name
    }

    func description() -> String {
        return age != nil ? "\(name) is \(age) years old." : "\(name) hides his age."
    }
}

var me = Student(name: "Daniel")
println(me.description())
me.age = 18
println(me.description())

Der obige Code erzeugt wie folgt

Daniel hides his age.
Daniel is Optional(18) years old.

Meine Frage ist, warum es dort Optional (18) gibt, wie ich das Optionale entfernen und nur drucken kann

Daniel is 18 years old.
Daniel Adinugroho
quelle

Antworten:

190

Sie müssen verstehen, was ein Optional wirklich ist. Viele Swift-Anfänger denken var age: Int?, dass Alter ein Int ist, das einen Wert haben kann oder nicht. Dies bedeutet jedoch, dass das Alter eine Option ist, die ein Int enthalten kann oder nicht.

Innerhalb Ihrer description()Funktion drucken Sie nicht das Int, sondern das Optionale. Wenn Sie das Int drucken möchten, müssen Sie das Optionale auspacken. Sie können "optionale Bindung" verwenden, um eine Option zu entpacken:

if let a = age {
 // a is an Int
}

Wenn Sie sicher sind, dass die Option ein Objekt enthält, können Sie "erzwungenes Auspacken" verwenden:

let a = age!

Da Sie in Ihrem Beispiel bereits einen Test für Null in der Beschreibungsfunktion haben, können Sie ihn einfach ändern in:

func description() -> String {
    return age != nil ? "\(name) is \(age!) years old." : "\(name) hides his age."
}
Apfelsaft
quelle
Ich denke, das Beispiel wäre etwas besser, wenn Sie es ändern würden, um zu verwendenif let age = age { return ""} else { return "" }
kubi
13
+1 für:Many Swift beginners think var age: Int? means that age is an Int which may or may not have a value. But it means that age is an Optional which may or may not hold an Int.
Lee
18

Optional 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 Auspacken 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!

GJZ
quelle
1
mit Rückgabealter! = Null? "(Name) ist (Alter!) Jahre alt." : "(Name) verbirgt sein Alter."
Leedream
1
Ersparte mir Kopfschmerzen mit einem Problem, das ich hatte. Ich kann dir nicht genug danken.
Bruno Recillas
8

Zu Test- / Debugging-Zwecken möchte ich häufig Optionen als Zeichenfolgen ausgeben, ohne immer auf nilWerte testen zu müssen. Deshalb habe ich einen benutzerdefinierten Operator erstellt.

Nachdem ich diese Antwort in einer anderen Frage gelesen hatte, verbesserte ich die Dinge noch weiter .

fileprivate protocol _Optional {
    func unwrappedString() -> String
}

extension Optional: _Optional {
    fileprivate func unwrappedString() -> String {
        switch self {
        case .some(let wrapped as _Optional): return wrapped.unwrappedString()
        case .some(let wrapped): return String(describing: wrapped)
        case .none: return String(describing: self)
        }
    }
}

postfix operator ~? { }
public postfix func ~? <X> (x: X?) -> String {
    return x.unwrappedString
}

Natürlich kann der Operator (und seine Attribute) nach Ihren Wünschen angepasst werden, oder Sie können ihn stattdessen zu einer Funktion machen. Auf diese Weise können Sie einfachen Code wie folgt schreiben:

var d: Double? = 12.34
print(d)     // Optional(12.34)
print(d~?)   // 12.34
d = nil
print(d~?)   // nil

Durch die Integration der Protokollidee des anderen wurde dies sogar so, dass dies sogar mit verschachtelten Optionen funktioniert, die häufig bei Verwendung der optionalen Verkettung auftreten. Beispielsweise:

let i: Int??? = 5
print(i)              // Optional(Optional(Optional(5)))
print("i: \(i~?)")    // i: 5
Jeremy
quelle
1
Ab Swift 3 können Sie auch die Swift-Standardbibliotheksfunktion debugPrint (_: separator: terminator :) verwenden. Dadurch wird die Zeichenfolge jedoch in doppelte Anführungszeichen gedruckt.
Psmythirl
@psmythirl: Gut zu wissen! Manchmal möchten Sie jedoch einfach ein optionales Element an einer Stringanderen Stelle übergeben oder einbetten (z. B. ein Protokoll / eine Fehlermeldung).
Jeremy
print (d as Any)
DawnSong
7

Aktualisieren

Einfach benutzen me.age ?? "Unknown age!". Es funktioniert in 3.0.2.

Alte Antwort

Ohne gewaltsames Auspacken (kein Mach-Signal / Absturz, wenn nichts) wäre eine andere gute Möglichkeit, dies zu tun:

(result["ip"] ?? "unavailable").description.

result["ip"] ?? "unavailable" sollte auch funktionieren, tut es aber nicht, zumindest nicht in 2.2

Ersetzen Sie "nicht verfügbar" durch das, was zu Ihnen passt: "null", "nicht gefunden" usw.

Valentin Radu
quelle
4

Zum Auspacken der optionalen Verwendung age!anstelle von age. Derzeit drucken Sie einen optionalen Wert, der sein könnte nil. Deshalb wickelte es mit Optional.

Kirsteins
quelle
4

In schnell Optionalist etwas, was nilin einigen Fällen sein kann. Wenn Sie zu 100% sicher sind, dass a variableimmer einen Wert hat und nildas Add nicht !mit der Variablen zurückgibt, um das Entpacken zu erzwingen.

In anderen Fällen, wenn Sie sich des Werts nicht sicher sind, fügen Sie einen if letBlock hinzu oder guardstellen Sie sicher, dass der Wert vorhanden ist. Andernfalls kann dies zu einem Absturz führen.

Für if letBlock:

if let abc = any_variable {
 // do anything you want with 'abc' variable no need to force unwrap now.
}

Zur guardAussage:

guard ist eine bedingte Struktur zur Rückgabe der Steuerung, wenn die Bedingung nicht erfüllt ist.

Ich bevorzuge in vielen Situationen die Verwendung von guardover if letblock, da wir damit den functionWert zurückgeben können, wenn ein bestimmter Wert nicht vorhanden ist. Wie wenn es eine Funktion gibt, bei der eine Variable als Integral vorhanden ist, können wir sie in der Guard-Anweisung überprüfen, und die Rückgabe existiert nicht. dh;

guard let abc = any_variable else { return }

Wenn eine Variable existiert, können wir 'abc' in der Funktion außerhalb des Schutzbereichs verwenden.

Muhammad Yawar Ali
quelle
3

ageist ein optionaler Typ: Optional<Int>Wenn Sie ihn also mit nil vergleichen, wird jedes Mal false zurückgegeben, wenn er einen Wert hat oder nicht. Sie müssen das Optionale auspacken, um den Wert zu erhalten.

In Ihrem Beispiel wissen Sie nicht, dass es einen Wert enthält, sodass Sie diesen stattdessen verwenden können:

if let myAge = age {
    // there is a value and it's currently undraped and is stored in a constant
}
else {
   // no value
}
Greg
quelle
3

Ich habe dies getan, um den Wert der Zeichenfolge (Eigenschaft) von einem anderen Ansichts-Controller zu drucken.

ViewController.swift

var testString:NSString = "I am iOS Developer"

SecondViewController.swift

var obj:ViewController? = ViewController(nibName: "ViewController", bundle: nil)
print("The Value of String is \(obj!.testString)")

Ergebnis:

The Value of String is I am iOS Developer
iCodeAtApple
quelle
2
Sie sollten nicht zwingen, ein optionales
E-Riddie
3

Schauen Sie sich die guardErklärung an:

for student in class {
    guard let age = student.age else { 
        continue 
     }
    // do something with age
}
Phil Hudson
quelle
3

Bei einem Standardwert:

print("\(name) is \(age ?? 0) years old")

oder wenn der Name optional ist:

print("\(name ?? "unknown") is \(age) years old")

Arnon
quelle
1

Ich habe das Optionale ("Zeichenfolge") in meinen Tabellenansichtszellen erhalten.

Die erste Antwort ist großartig. Und hat mir geholfen, es herauszufinden. Hier ist, was ich getan habe, um den Neulingen da draußen wie mir zu helfen.

Da ich in meinem benutzerdefinierten Objekt ein Array erstelle, weiß ich, dass sich immer Elemente an der ersten Position befinden, sodass ich das Entpacken in eine andere Variable erzwingen kann. Verwenden Sie dann diese Variable, um zu drucken, oder setzen Sie in meinem Fall den Zelltext der Tabellenansicht.

let description = workout.listOfStrings.first!
cell.textLabel?.text = description

Scheint jetzt so einfach, aber ich habe eine Weile gebraucht, um es herauszufinden.

Joshua Dance
quelle
-1

Dies ist nicht die genaue Antwort auf diese Frage, sondern ein Grund für diese Art von Problem. In meinem Fall konnte ich Optional nicht mit "if let" und "guard let" aus einem String entfernen.

Verwenden Sie also AnyObject anstelle von Any , um optional schnell aus einer Zeichenfolge zu entfernen.

Bitte beziehen Sie sich auf den Link für die Antwort.

https://stackoverflow.com/a/51356716/8334818

Pramod Mehr
quelle