2014-09-02 10 views
6

Ich mache, was ich glaube, eine sehr einfache Aufgabe. Ich versuche, einen Wert aus einem Wörterbuch zu erhalten, wenn der Schlüssel existiert. Ich mache dies für ein paar Schlüssel im Wörterbuch und dann ein Objekt erstellen, wenn sie alle existieren (im Grunde ein JSON-Objekt dekodieren). Ich bin neu in der Sprache, aber dies scheint mir, wie es funktionieren sollte, noch nicht:Schnelle Optionen: Sprachproblem oder etwas falsch machen?

class func fromDict(d: [String : AnyObject]!) -> Todo? { 
    let title = d["title"]? as? String 
    // etc... 
} 

Es gibt mir den Fehler: Operand of postfix ? should have optional type; type is (String, AnyObject)

jedoch, wenn ich das tue, funktioniert es:

class func fromDict(d: [String : AnyObject]!) -> Todo? { 
    let maybeTitle = d["title"]? 
    let title = maybeTitle as? String 
    // etc... 
} 

Es scheint, grundlegende Substitution sein, aber ich kann etwas Nuance der Sprache fehlen. Könnte irgendjemand etwas Licht darauf werfen?

+0

'd [" title "]' ist optional, Sie verwenden '?' Nach einem optionalen Fehler. Ein Anwendungsfall für diesen Operator wäre "object? .property", so dass nur "object.property" ausgewertet wird, wenn "object" nicht ** 'nil' ist, sonst gibt es' nil' zurück – Binarian

Antwort

3

Die empfohlene Muster ist

if let maybeTitle = d["title"] as? String { 
    // do something with maybeTitle 
} 
else { 
    // abort object creation 
} 

Es ist vielleicht wirklich eine Frage von Nuance. Das Formular array[subscript]? ist mehrdeutig, weil es bedeuten könnte, dass das gesamte Wörterbuch (<String:AnyObject>) optional ist, während Sie wahrscheinlich das Ergebnis meinen (String). Im obigen Muster nutzen Sie die Tatsache, dass Dictionary so ausgelegt ist, dass angenommen wird, dass der Zugriff auf einige Schlüssel einen optionalen Typ ergibt.

Nach dem Experimentieren, und bemerkte, dass die ? nach as ebenso zweideutig ist, mehr, hier ist meine Lösung:

var dictionary = ["one":"1", "two":"2"] 
// or var dictionary = ["one":1, "two":2] 
var message = "" 
if let three = dictionary["three"] as Any? { 
    message = "\(three)" 
} 
else { 
    message = "No three available." 
} 
message // "No three available." 

Dies mit allen Nicht-Objekt Swift Objekte funktionieren würde, einschließlich Swift Strings, Zahlen usw. Vielen Dank an Viktor für die Erinnerung an , dass String kein Objekt in Swift ist. +

Wenn Sie die Art des Wertes kennen Sie Any? mit der entsprechenden optionalen Art, wie String?

+0

Ich dachte es auch , ** aber ** das wirft einen Fehler auf den Spielplatz, wie @vacawama erwähnt. Der 'NSString' im Dictionary als Wert wird als Typ von' (String, AnyType) 'angezeigt und kann nicht in derselben Zeile in' String? 'Umgewandelt werden. ... Und dein * vielleichtTitel * wäre vielleicht nicht mehr, sonst wäre es nicht richtig eingestellt, bevor ich in die if-Klammern gehe. – Binarian

+0

Was passiert, wenn das Wörterbuch vom Typ '[String: AnyObject]!' Ist, wie das Wörterbuch des OP. Das funktioniert auf einem Spielplatz nicht für mich. – vacawama

+0

'wenn let drei = Wörterbuch [" drei "] als NSObject?' Funktioniert, wenn das Wörterbuch '[String: AnyObject]!'. – vacawama

2

Es gibt ein paar Dinge, die sie hier ersetzen.

1) Die ? in d["title"]? wird nicht korrekt verwendet. Wenn Sie versuchen, d["title"] auszupacken, dann verwenden Sie eine !, aber seien Sie vorsichtig, denn dies stürzt ab, wenn title kein gültiger Schlüssel in Ihrem Wörterbuch ist. (Die ? wird für optionale Verkettung verwendet wie wenn Sie versuchten, eine Methode auf eine optionale Variable oder Zugriff auf eine Eigenschaft aufrufen. In diesem Fall würde der Zugriff nur nichts tun, wenn die optionalen waren nil). Es scheint nicht, dass Sie versuchen, d["title"] auszupacken, also lassen Sie die ? weg. Ein Wörterbuchzugriff gibt immer einen optionalen Wert zurück, da der Schlüssel möglicherweise nicht vorhanden ist.

2) Wenn Sie das beheben waren:

let maybeTitle = d["title"] as? String 

Die Fehlermeldung erscheint: Fehler: '(String, ANYOBJECT)' ist nicht konvertierbar 'String'

Das Problem hier ist, dass ein String kein Objekt ist. Sie müssen in NSString umwandeln.

let maybeTitle = d["title"] as? NSString 

führen Dies wird in maybeTitle ein NSString? zu sein. Wenn nicht existiert oder wenn der Typ wirklich NSNumber anstelle von NSString ist, dann wird das Optional einen Wert von nil haben, aber die App wird nicht abstürzen.

3) Ihre Aussage:

let title = maybeTitle as? String 

nicht die optionale Variable auszupacken, wie Sie möchten. Die richtige Form ist:

if let title = maybeTitle as? String { 
    // title is unwrapped and now has type String 
} 

Damit alle zusammen setzen:

if let title = d["title"] as? NSString { 
    // If we get here we know "title" is a valid key in the dictionary, and 
    // we got the type right. title has now been unwrapped and is ready to use 
} 

title den Typ NSString haben, das ist das, was im Wörterbuch gespeichert wird, da es Objekte enthält. Sie können mit NSString meisten alles tun, was Sie mit String tun können, aber wenn Sie title brauchen eine String zu sein, dies zu tun:

if var title:String = d["title"] as? NSString { 
    title += " by Poe" 
} 

und wenn Ihr Wörterbuch hat NSNumber s auch:

if var age:Int = d["age"] as? NSNumber { 
    age += 1 
} 
+0

Da gibt es automatische Übersetzung zwischen NSString und String; Sie speichern einen NSString in einem String ohne Casting. Es ist nur verwirrend, NSString überhaupt zu verwenden, wenn String gewünscht wird. – Binarian

+1

Es ist eine Schande, dass wir 'NSString' verwenden müssen, aber das ist eine Tatsache des Lebens, wenn es um Wörterbücher geht, die von Cocoa und Cocoa Touch Calls kommen. Wenn das Wörterbuch "[String: Any]" gewesen wäre, wäre das Leben viel einfacher gewesen. – vacawama

+0

Wie bei jedem NSObject ist NSString bereits optional, so dass man '' '' '' '' '' ' – Binarian

Verwandte Themen