La raison de cette confusion est que as?
a deux significations complètement orthogonales dans Swift, selon le contexte. Lorsque vous traitez avec des types purement Swift, as?
est une distribution dynamique qui retourne nil
non seulement si le type est littéralement une instance du type sur le côté droit de l'opérateur as?
:
import Foundation
let dict: [String : Any] = ["Foo" : 3 as Int]
print(dict["Foo"] as? Int)
print(dict["Foo"] as? Int32)
print(dict["Foo"] as? Int64)
Ce retourne Optional(3)
pour la premier journal, et nil
pour les deux autres, car le type est un Int
et non un Int32
ou un Int64
.
Cependant, lorsque le type de l'élément en cours de coulée est un de type Objective-C, alors as?
n'est plus une distribution dynamique stricte, mais provoque plutôt pont comportement:
import Foundation
let dict: [String : Any] = ["Foo" : 3 as NSNumber]
print(dict["Foo"] as? Int)
print(dict["Foo"] as? Int32)
print(dict["Foo"] as? Int64)
Ce rendement Optional(3)
pour les trois journaux, car il ne s'agit plus d'une distribution dynamique. En effet, une instance NSNumber
ne fait partie d'aucun des trois types auxquels nous avons tenté de procéder. Au lieu de cela, as?
provoque Swift à pont le type Objective-C, NSNumber
, à un type Swift approprié si possible. Depuis que Swift a la logique pour combler NSNumber
à Int
, Int32
, et Int64
(avec une foule d'autres types numériques), nous obtenons Optional(3)
pour les trois journaux. Cependant, si vous tentez de lancer vers quelque chose comme Decimal
pour lequel il n'y a pas de logique de pontage NSNumber
, vous obtenez toujours nil
.
Un intéressant effet secondaire de ceci est que as?
ne suit pas la propriété transitive:
let foo: Int = 3
print(foo as? NSNumber as? Int64) // Optional(3)
print(foo as? Int64) // nil
Quoi qu'il en soit, si vous lancez vos valeurs NSNumber
d'abord, vous devriez alors être en mesure de jeter de là à tout des types numériques que supporte le pont Objective-C, ce qui est probablement ce qui se passait sous le capot avec votre ancien code Swift 3. Par ailleurs, si vous connaissez réellement le type que la valeur est censée être, vous pouvez utiliser l'un des autres les initialiseurs de types entiers:
let dict: [String : Any] = ["Foo" : 3 as Int]
let foo = (dict["Foo"] as? Int).map { Int32($0) }
Si vous avez des problèmes de JSON spécifiques, s'il vous plaît montrer le JSON et le code utilisons pour l'analyser. – Sulthan
Le code ci-dessus ne montre rien concernant JSON. '[String: Any]' est "un dictionnaire de String pour absolument tout type de données qui peut être exprimé dans Swift."Ceci est souvent mal utilisé pour JSON, mais l'analyse de JSON avec NSJSONSerialization ne devrait jamais générer le dictionnaire que vous avez donné ici.Sans rien ci-dessus est" insensé ", il semble suivre exactement les règles, il peut donc être utile d'expliquer le problème JSON n'a pas de type entier 32 bits ou 64 bits –
Notez que Int de Swift correspond à NSInteger de ObjC, et (comme dans ObjC) est le type recommandé pour presque toutes les choses "entières" dans Swift Les largeurs de bits spécifiques sont fortement déconseillées, sauf si elles sont requises pour des interactions de bas niveau ou pour garantir de très grands entiers sur une plate-forme 32 bits.Ils ne sont pas conçus pour être utilisés en général dans Swift. Vous voulez être averti lorsque vous ne respectez pas les exigences de taille. –