Opciones rápidas: ¿problema de idioma o hacer algo mal?

Estoy haciendo lo que creo que es una tarea muy simple. Estoy intentando get un valor de un dictionary si existe la key. Estoy haciendo esto por un par de keys en el dictionary y luego creando un object si todos existen (básicamente decodificando un object JSON). Soy nuevo en el idioma, pero me parece que debería funcionar, pero no lo hace:

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

Me da el error: ¿ Operand of postfix ? should have optional type; type is (String, AnyObject) Operand of postfix ? should have optional type; type is (String, AnyObject)

SIN EMBARGO, si hago esto, funciona:

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

Parece ser una sustitución básica, pero puede que me falte algo de matiz del idioma. ¿Alguien podría arrojar algo de luz sobre esto?

El patrón recomendado es

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

Es posible que realmente sea una cuestión de matices. La array[subscript]? forms array[subscript]? es ambiguo porque podría significar que todo el dictionary ( <String:AnyObject> ) es opcional mientras que probablemente signifique el resultado ( String ). En el patrón anterior, aprovecha el hecho de que el Dictionary está diseñado para asumir que acceder a algunos resultados key en un tipo opcional.

Después de experimentar y de notar que ? después de lo as es igual de ambiguo, más, aquí está mi solución:

 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." 

Esto funcionaría con todos los objects Swift que no sean objects, incluidas Swift Strings, numbers, etc. Gracias a Viktor por recordarme que String no es un object en Swift . +

Si conoce el tipo de valores, ¿puede sustituirlo Any? con el tipo opcional apropiado, como String?

Hay algunas cosas que suceden aquí.

1) ? El ? en d["title"]? No es el uso correcto. Si está tratando de desenvolver d["title"] entonces use un ! pero tenga cuidado porque esto se bloqueará si el title no es una key válida en su dictionary. (El ? Se usa para encadenar opcionalmente como si estuviera intentando llamar a un método en una variable opcional o acceder a una propiedad. En ese caso, el acceso no haría nada si los opcionales fueran nil ). No parece que está tratando de desenvolver d["title"] así que ¿dejar de lado el ? . Un acceso de dictionary siempre devuelve un valor opcional porque la key podría no existir.

2) Si tuvieras que arreglar eso:

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

El post de error cambia a: error: '(String, AnyObject)' no es convertible a 'String'

El problema aquí es que una String no es un object. Debes NSString a NSString .

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

Esto resultará en maybeTitle siendo un NSString? . Si d["title"] no existe o si el tipo es realmente NSNumber lugar de NSString , entonces el opcional tendrá un valor de nil pero la aplicación no se bloqueará.

3) Su statement:

 let title = maybeTitle as? String 

no desenvuelve la variable opcional como desee. La forma correcta es:

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

Así que poniéndolo todo junto:

 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 tendrá el tipo NSString que es lo que está almacenado en el dictionary, ya que contiene objects. Puedes hacer casi todo con NSString que puedes hacer con String , pero si necesitas un title para ser un String , puedes hacer esto:

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

y si su dictionary tiene NSNumber s también:

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