Options de Downcasting dans Swift: as? Type, ou en tant que! Le Type?
étant donné ce qui suit dans Swift:
var optionalString: String?
let dict = NSDictionary()
Quelle est la différence pratique entre les deux énoncés suivants:
optionalString = dict.objectForKey("SomeKey") as? String
vs
optionalString = dict.objectForKey("SomeKey") as! String?
9 réponses
la différence pratique est la suivante:
var optionalString = dict["SomeKey"] as? String
optionalString
sera une variable de type String?
. Si le type sous-jacent est autre chose qu'un String
cela assignera simplement nil
à l'optionnel.
var optionalString = dict["SomeKey"] as! String?
cela dit, je savoir cette chose est un String?
. Il en résultera aussi que optionalString
est de type String?
, mais il s'écrasera si le type sous-jacent est autre chose.
le premier style est ensuite utilisé avec if let
pour déballer en toute sécurité l'option:
if let string = dict["SomeKey"] as? String {
// If I get here, I know that "SomeKey" is a valid key in the dictionary, I correctly
// identified the type as String, and the value is now unwrapped and ready to use. In
// this case "string" has the type "String".
print(string)
}
pour clarifier ce que vacawama a dit, Voici un exemple...
Swift 3.0:
import UIKit
let str_value: Any = String("abc")!
let strOpt_value: Any? = String("abc")!
let strOpt_nil: Any? = (nil as String?)
let int_value: Any = Int(1)
let intOpt_value: Any? = Int(1)
let intOpt_nil: Any? = (nil as Int?)
// as String
//str_value as String // Compile-Time Error: 'Any' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//strOpt_value as String // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//strOpt_nil as String // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//int_value as String // Compile-Time Error: 'Any' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//intOpt_value as String // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//intOpt_nil as String // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
// as? String
str_value as? String // == "abc"
strOpt_value as? String // == "abc"
strOpt_nil as? String // == nil
int_value as? String // == nil
intOpt_value as? String // == nil
intOpt_nil as? String // == nil
// as! String
str_value as! String // == "abc"
strOpt_value as! String // == "abc"
//strOpt_nil as! String // Run-Time Error: unexpectedly found nil while unwrapping an Optional value.
//int_value as! String // Run-Time Error: Could not cast value of type 'Swift.Int' to 'Swift.String'.
//intOpt_value as! String // Run-Time Error: Could not cast value of type 'Swift.Int' to 'Swift.String'.
//intOpt_nil as! String // Run-Time Error: unexpectedly found nil while unwrapping an Optional value.
// as String?
//str_value as String? // Compile-Time Error: cannot convert value of type 'Any' to type 'String?' in coercion
//strOpt_value as String? // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast?
//strOpt_nil as String? // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast?
//int_value as String? // Compile-Time Error: cannot convert value of type 'Any' to type 'String?' in coercion
//intOpt_value as String? // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast?
//intOpt_nil as String? // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast?
// as? String?
//str_value as? String? // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?'
strOpt_value as? String? // == "abc"
strOpt_nil as? String? // == nil
//int_value as? String? // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?'
intOpt_value as? String? // == nil
intOpt_nil as? String? // == nil
// as! String?
//str_value as! String? // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?'
strOpt_value as! String? // == "abc"
strOpt_nil as! String? // == nil
//int_value as! String? // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?'
//intOpt_value as! String? // Run-Time Error: Could not cast value of type 'Swift.Int' to 'Swift.String'.
intOpt_nil as! String? // == nil
// let _ = ... as String
//if let _ = str_value as String { true } // Compile-Time Error: 'Any' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//if let _ = strOpt_value as String { true } // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//if let _ = strOpt_nil as String { true } // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//if let _ = int_value as String { true } // Compile-Time Error: 'Any' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//if let _ = intOpt_value as String { true } // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//if let _ = intOpt_nil as String { true } // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
// let _ = ... as? String
if let _ = str_value as? String { true } // true
if let _ = strOpt_value as? String { true } // true
if let _ = strOpt_nil as? String { true } // false
if let _ = int_value as? String { true } // false
if let _ = intOpt_value as? String { true } // false
if let _ = intOpt_nil as? String { true } // false
// let _ = ... as! String
//if let _ = str_value as! String { true } // Compile-Time Error: initializer for conditional binding must have Optional type, not 'String'
//if let _ = strOpt_value as! String { true } // Compile-Time Error: initializer for conditional binding must have Optional type, not 'String'
//if let _ = strOpt_nil as! String { true } // Compile-Time Error: initializer for conditional binding must have Optional type, not 'String'
//if let _ = int_value as! String { true } // Compile-Time Error: initializer for conditional binding must have Optional type, not 'String'
//if let _ = intOpt_value as! String { true } // Compile-Time Error: initializer for conditional binding must have Optional type, not 'String'
//if let _ = intOpt_nil as! String { true } // Compile-Time Error: initializer for conditional binding must have Optional type, not 'String'
// let _ = ... as String?
//if let _ = str_value as String? { true } // Compile-Time Error: cannot convert value of type 'Any' to type 'String?' in coercion
//if let _ = strOpt_value as String? { true } // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast?
//if let _ = strOpt_nil as String? { true } // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast?
//if let _ = int_value as String? { true } // Compile-Time Error: cannot convert value of type 'Any' to type 'String?' in coercion
//if let _ = intOpt_value as String? { true } // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast?
//if let _ = intOpt_nil as String? { true } // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast?
// let _ = ... as? String?
//if let _ = str_value as? String? { true } // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?'
if let _ = strOpt_value as? String? { true } // true
if let _ = strOpt_nil as? String? { true } // true
//if let _ = int_value as? String? { true } // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?'
if let _ = intOpt_value as? String? { true } // false
if let _ = intOpt_nil as? String? { true } // true
// let _ = ... as! String?
//if let _ = str_value as! String? { true } // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?'
if let _ = strOpt_value as! String? { true } // true
if let _ = strOpt_nil as! String? { true } // false
//if let _ = int_value as! String? { true } // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?'
//if let _ = intOpt_value as! String? { true } // Run-Time Error: Could not cast value of type 'Swift.Int' to 'Swift.String'.
if let _ = intOpt_nil as! String? { true } // false
Swift 2.0:
import UIKit
let str: AnyObject = String("abc")
let strOpt: AnyObject? = String("abc")
let strNil: AnyObject? = (nil as String?)
let int: AnyObject = Int(1)
let intOpt: AnyObject? = Int(1)
let intNil: AnyObject? = (nil as Int?)
str as? String // == "abc"
strOpt as? String // == "abc"
strNil as? String // == nil
int as? String // == nil
intOpt as? String // == nil
intNil as? String // == nil
str as! String? // Compile-Time Error: Cannot downcast from 'AnyObject' to a more optional type 'String?'
strOpt as! String? // == "abc"
strNil as! String? // == nil
int as! String? // Compile-Time Error: Cannot downcast from 'AnyObject' to a more optional type 'String?'
intOpt as! String? // Run-Time Error: Could not cast value of type '__NSCFNumber' to 'NSString'
intNil as! String? // == nil
as? Types
- le procédé de coulée vers le bas est facultatif. Le processus peut être réussi ou non(le système retournera zéro si la coulée vers le bas échoue).Aucun moyen ne s'écrasera si down casting échoue.
as! Type?
- ici, le procédé de coulée vers le bas devrait être couronné de succès ( !
indique que) . Le point d'interrogation final indique si le résultat final peut être nul ou non.
Plus d'infos à propos des "!"et "?"
prenons 2 cas
-
prendre en considération:
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as? UITableViewCell
ici, nous ne savons pas si le résultat de la fonte de la cellule avec l'identificateur "Cell" à Uitable Viewcell est le succès ou non. En cas d'échec, il renvoie zéro( donc nous évitons de nous écraser ici). Ici, nous pouvons faire comme indiqué ci-dessous.
if let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as? UITableViewCell { // If we reached here it means the down casting was successful } else { // unsuccessful down casting }
alors souvenons - nous comme ceci- si
?
cela signifie que nous ne sommes pas sûr si la valeur est nulle ou pas (le point d'interrogation vient quand on ne sait pas des choses). -
contraste avec:
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! UITableViewCell.
ici, nous disons au compilateur que la coulée vers le bas devrait être réussie. Si elle échoue, le système se bloque. Nous donnons donc
!
quand nous sommes sûrs que la valeur n'est pas nulle.
il s'agit de deux formes différentes de Downcasting dans Swift.
( as?
) , qui est connu pour être le Conditionnel , renvoie une valeur optionnelle de type que vous essayez d'baissés.
Vous pouvez l'utiliser lorsque vous n'êtes pas sûr si les humbles va réussir. Cette forme de l'opérateur retourne toujours une valeur facultative, et valeur sera nul si les humbles n'était pas possible. Cela permet vous recherchez un succès abattu.
( as!
) , qui est connu pour être la forme forcée , tente le downcast et force-déroule le résultat comme une action composée simple.
Vous devriez l'utiliser SEULEMENT lorsque vous êtes sûr que les humbles seront toujours réussir. Cette forme de l'opérateur déclenche une exécution erreur si vous essayez de downcast à un type de classe incorrect.
pour plus de détails, veuillez consulter la section Type Casting de la documentation D'Apple.
-
as
utilisé pour l'upcasting et le type de coulée à type ponté -
as?
utilisé pour la coulée sûre, retour néant en cas de défaillance -
as!
utilisé pour forcer le moulage, se crash if failed
Note:
-
as!
ne pouvez pas jeter raw type facultatif
exemples:
let rawString: AnyObject = "I love swift"
let optionalString: AnyObject? = "we love swift"
let nilString: AnyObject? = (nil as String?)
let rawInt: AnyObject = Int(3)
let optionalInt: AnyObject? = Int(3)
let nilInt: AnyObject? = (nil as Int?)
exemple
var age: Int? = nil
var height: Int? = 180
en ajoutant un ? immédiatement après le type de données, vous dites au compilateur que la variable peut contenir un nombre ou pas. Soigné! Notez qu'il n'est pas vraiment logique de définir des constantes optionnelles – vous pouvez définir leur valeur qu'une seule fois et donc vous seriez en mesure de dire si leur valeur sera nulle ou non.
Quand on doit utiliser "?"et lorsque "!"
disons que nous avons UIKit basé application simple. nous avons du code dans notre contrôleur de vue et nous voulons présenter un nouveau contrôleur de vue dessus. et nous devons décider de pousser la nouvelle vue sur l'écran en utilisant le contrôleur de navigation.
comme nous le savons, chaque instance de ViewController possède un contrôleur de navigation de propriété. Si vous construisez une application basée sur un contrôleur de navigation, cette propriété du contrôleur de vue maître de votre application est réglée automatiquement et vous pouvez l'utiliser pour pousser ou contrôleurs de vue pop. Si vous utilisez un modèle de projet app unique – il n'y aura pas de contrôleur de navigation créé automatiquement pour vous, de sorte que le contrôleur de vue par défaut de votre application n'aura rien stocké dans la propriété navigationController.
je suis sûr que vous avez déjà deviné que c'est exactement un cas pour un type de données optionnel. Si vous vérifiez UIViewController vous verrez que la propriété est définie comme:
var navigationController: UINavigationController? { get }
alors revenons à notre cas d'utilisation. Si vous savez pour un fait que votre contrôleur de vue aura toujours un contrôleur de navigation, vous pouvez aller de l'avant et forcer la décompression:
controller.navigationController!.pushViewController(myViewController, animated: true)
Quand vous mettez un ! derrière le nom de la propriété, vous dites au compilateur je me fiche que cette propriété soit optionnelle, je sais que lorsque ce code s'exécute il y aura toujours un magasin de valeurs alors traitez cette optionnelle comme un type de données normal. N'est-ce pas agréable? Ce serait se produit cependant s'il n'y a pas un contrôleur de navigation à votre contrôleur de vue? Si vous suggérez qu'il y aura toujours une valeur stockée dans navigationController était erroné? Votre application va s'écraser. Simple et laid comme ça.
donc, utilisez ! seulement si vous êtes 101% sûr que c'est sûr.
et si vous n'êtes pas sûr qu'il y aura toujours un contrôleur de navigation? Vous pouvez ensuite utiliser ? au lieu d'un !:
controller.navigationController?.pushViewController(myViewController, animated: true)
que se passe-t-il ? derrière le nom de la propriété dit le compilateur est Je ne sais pas si cette propriété contient zéro ou une valeur, donc: si elle a de la valeur l'utiliser, et oterwise juste considérer l'expression entière nul. effectivement le ? vous permet d'utiliser cette propriété dans le cas où il y a une manette de navigation. Aucun, si des contrôles de toute nature ou de coulées de toute sorte. Cette syntaxe est parfaite quand vous ne vous souciez pas si vous avez un contrôleur de navigation ou pas, et veulent faire quelque chose que s'il ya.
Merci beaucoup à Fantageek
peut-être que cet exemple de code aidera quelqu'un grok le principe:
var dict = [Int:Any]()
dict[1] = 15
let x = dict[1] as? String
print(x) // nil because dict[1] is an Int
dict[2] = "Yo"
let z = dict[2] as! String?
print(z) // optional("Yo")
let zz = dict[1] as! String // crashes because a forced downcast fails
let m = dict[3] as! String?
print(m) // nil. the forced downcast succeeds, but dict[3] has no value
la première est une "coulée conditionnelle" (regardez sous "opérateurs de coulée par type" dans la documentation que j'ai liée) . Si la fonte réussit, la valeur de l'expression est enveloppée dans une option et retournée, sinon la valeur retournée est nulle.
la seconde signifie que optionalString pourrait être un objet string ou il pourrait être nul.
il est peut-être plus facile de se rappeler le modèle pour ces opérateurs dans Swift comme suit: !
implique" cela pourrait piéger", tandis que ?
indique" cela pourrait être nul."
se référer à: https://developer.apple.com/swift/blog/?id=23
je suis novice pour Swift et j'écris cet exemple en essayant d'expliquer ce que je comprends au sujet des "optionnels". Si je me trompe merci de me corriger.
Merci.
class Optional {
var lName:AnyObject! = "1"
var lastName:String!
}
let obj = Optional()
print(obj.lName)
print(obj.lName!)
obj.lastName = obj.lName as? String
print(obj.lastName)
(1) : obj.lastName = obj.lName as! String
vs
(2) : obj.lastName = obj.lName as? String
Ans: (1) ici programmeur est damm sûr que “obj.lName”
contient le type de chaîne de caractères objet. Donnez cette valeur à “obj.lastName”
.
maintenant, si programmeur est correct signifie "obj.lName"
est un objet de type chaîne, alors pas de problème. "obj.lastName " se positionnera à la même valeur.
mais si le programmeur a tort signifie "obj.lName"
n'est pas un objet de type chaîne, c'est-à-dire qu'il contient un autre objet de type comme" NSNumber " etc. Puis CRASH (erreur de temps D'exécution).
(2) Programmeur n'est pas sûr que “obj.lName”
contient chaîne tapez objet ou n'importe quel autre type d'objet. Ainsi, définissez cette valeur à “obj.lastName”
si c'est un type de chaîne.
maintenant, si programmeur est correct signifie “obj.lName”
est un objet de type chaîne, alors pas de problème. “obj.lastName”
définira la même valeur.
mais si programmeur se trompe signifie obj.lName n'est pas un objet de type string, c'est-à-dire qu'il contient un autre objet de type comme "NSNumber"
, etc. Ensuite “obj.lastName”
sera mis à la valeur nulle. Donc, Pas D'Accident (Heureux:)