2016-06-05 15 views
2

Ich habe einige test code erstellt, um das Problem zu zeigen, das ich habe.Swift AnyObject Konvertierung

Dies kompiliert in einem Spielplatz, aber wenn ich versuche, es in ein Projekt zu setzen, Xcode gibt folgende Warnung: Treating a forced downcast to 'String' as optional will never produce 'nil' auf line 30. Ich bin zwei Vorschläge gegeben, das Problem zu beheben:

  1. Use 'as?' to perform a conditional downcast to 'String', die absolut keinen Sinn macht. Es kompiliert jedoch ohne Warnungen/Fehler, was merkwürdig erscheint, da es einem nicht optionalen Typ String einen optionalen Wert zuweist.

    Verwenden Sie die bedingte Form des Typs cast -Operator (als?), Wenn Sie nicht sicher sind, ob der Downcast erfolgreich sein wird. Diese Form des Operators gibt immer einen optionalen Wert zurück, und der Wert ist Null, wenn der Downcast nicht möglich war. Auf diese Weise können Sie nach einem erfolgreichen Downcast suchen.

    Von der Swift language guide.

    Wenn es nicht denkt, dass ich nil zuweisen möchte, wenn die Konvertierung fehlschlägt (daher den Wörterbucheintrag zu entfernen), macht dies keinen Sinn. Vor allem, weil ich sicher bin, dass es gelingen wird, weil ich buchstäblich nur überprüft habe, ob es ein String ist.

  2. Add parentheses around the cast to silence this warning, was sinnlos scheint, aber tut Stille die Warnung. Das scheint eine seltsame Sache zu sein, aber andererseits kann es nur eine schlechte Art sein zu bestätigen, dass du wirklich tun willst, was du versuchst zu tun.


Welche Option ist richtig, oder keines von beiden? Was verursacht diese Warnung?

+0

Es gibt viele Probleme mit diesem Code. Zuallererst müssen Sie die Rückgabetypen in Ihren Funktionen explizit umwandeln, damit sie ein 'AnyObject?' Zurückgeben. Zweitens sollten Sie das explizite Auspacken von "Optional" vermeiden, indem Sie '!' So oft wie möglich verwenden. – ColGraff

+0

@ originaluser2 Guter Punkt, ich habe meinen Code aktualisiert. – Coder256

+0

@ColGraff, der Punkt ist, dass die Funktionen Werte verschiedener Typen zurückgeben können (dies sind nur Beispiele). Warum sollte ich auch das explizite Auspacken von Optionals vermeiden (wenn ich bereits getestet habe, ob sie null waren)? – Coder256

Antwort

5

Die richtige Lösung ist die Verwendung der optionalen Bindung anstelle des erzwungenen Unwrap-Operators !. Eigentlich können Sie den Check value != nil in die switch Erklärung übernehmen:

for (key, value) in dict { 
    switch value { 
    case let s as String: 
     newDict[key] = s 
    case let i as Int: 
     newDict[key] = String(i) 
    case let b as Bool: 
     newDict[key] = b ? "1" : "0" 
    case let v?: // value is not `nil` 
     newDict[key] = String(v) 
    default:  // value is `nil` 
     break 
    } 
} 
+0

Ich war mir dieser Methode bewusst, aber sie scheint genauso zu funktionieren wie meine. Allerdings behebt es das Problem! – Coder256

+0

@ Coder256: Die Warnung scheint wirklich durch die Tatsache verursacht, dass der Typ der LHS optional ist. Beachten Sie jedoch, dass der Compiler möglicherweise nicht erkennt, dass Sie den Typ der Variablen bereits überprüft haben. Optionale Bindung vermeidet diese Probleme. –

0

Hier ist der Code, geändert zu zeigen, wie Sie eine Funktion Ergebnis werfen können AnyObject? anzupassen und zu vermeiden explizit ungeöffneten optionals:

func returnsAString() -> AnyObject? { 
    return "I am a String." as? AnyObject 
} 

func returnsAnInt() -> AnyObject? { 
    return Int(123) as? AnyObject 
} 

func returnsABool() -> AnyObject? { 
    return true as? AnyObject 
} 

func returnsNilBool() -> AnyObject? { 
    return nil as Bool? as? AnyObject 
} 

var dict : [String : AnyObject?] = [String : AnyObject?]() 
var newDict : [String : String ] = [String : String ]() 

dict["string"] = returnsAString() 
dict["int"] = returnsAnInt() 
dict["bool"] = returnsABool() 
dict["nil"] = returnsNilBool() 

for (key, value) in dict { 
    switch value { 
    case let value as String: 
     newDict[key] = value 
    case let value as Int: 
     newDict[key] = String(value) 
    case let value as Bool: 
     newDict[key] = (value ? "1" : "0") 
    default: 
     newDict[key] = "nil" 
    } 
} 

print("Dict: \(dict)") 
print("newDict: \(newDict)") 

// Dict: ["nil": nil, "int": Optional(123), "bool": Optional(1), "string": Optional(I am a String.)] 
// newDict: ["nil": "nil", "int": "123", "bool": "1", "string": "I am a String."]