353 votes

Comment imprimer le type ou la classe d'une variable en Swift ?

Existe-t-il un moyen d'imprimer le type d'exécution d'une variable dans swift ? Par exemple :

var now = NSDate()
var soon = now.dateByAddingTimeInterval(5.0)

println("\(now.dynamicType)") 
// Prints "(Metatype)"

println("\(now.dynamicType.description()")
// Prints "__NSDate" since objective-c Class objects have a "description" selector

println("\(soon.dynamicType.description()")
// Compile-time error since ImplicitlyUnwrappedOptional<NSDate> has no "description" method

Dans l'exemple ci-dessus, je cherche un moyen de montrer que la variable "soon" est de type ImplicitlyUnwrappedOptional<NSDate> ou au moins NSDate! .

44 votes

@JasonMArcher Dites-moi comment cela peut être un doublon si la question que vous avez liée a été posée 4 jours après celle-ci ?

0 votes

Il existe un certain nombre de questions concernant le test du type d'un objet Swift ou la lecture du type d'un objet Swift. Nous sommes en train de trouver les meilleures questions à utiliser comme questions "maîtresses" pour ce sujet. Le duplicata suggéré a une réponse beaucoup plus approfondie. Cela ne veut pas dire que vous avez fait quelque chose de mal, mais simplement que nous essayons de réduire le désordre.

4 votes

Le doublon proposé ne répond pas à la même question ; Type.self ne peut pas être imprimé sur la console à des fins de débogage, il est destiné à être utilisé pour passer à d'autres fonctions qui prennent les Types comme objets.

394voto

Klaas Points 2995

Mise à jour de septembre 2016

Swift 3.0 : Utilisez type(of:) par exemple type(of: someThing) (puisque le dynamicType a été supprimé)

Mise à jour octobre 2015 :

J'ai mis à jour les exemples ci-dessous avec la nouvelle syntaxe de Swift 2.0 (par ex. println a été remplacé par print , toString() est maintenant String() ).

Extrait des notes de publication de Xcode 6.3 :

@nschum fait remarquer dans les commentaires que la Notes de publication de Xcode 6.3 montrer une autre voie :

Les valeurs de type s'impriment désormais sous la forme du nom complet du type démêlé lorsqu'elles sont utilisées avec la commande println ou l'interpolation de chaîne.

import Foundation

class PureSwiftClass { }

var myvar0 = NSString() // Objective-C class
var myvar1 = PureSwiftClass()
var myvar2 = 42
var myvar3 = "Hans"

print( "String(myvar0.dynamicType) -> \(myvar0.dynamicType)")
print( "String(myvar1.dynamicType) -> \(myvar1.dynamicType)")
print( "String(myvar2.dynamicType) -> \(myvar2.dynamicType)")
print( "String(myvar3.dynamicType) -> \(myvar3.dynamicType)")

print( "String(Int.self)           -> \(Int.self)")
print( "String((Int?).self         -> \((Int?).self)")
print( "String(NSString.self)      -> \(NSString.self)")
print( "String(Array<String>.self) -> \(Array<String>.self)")

Quelles sorties :

String(myvar0.dynamicType) -> __NSCFConstantString
String(myvar1.dynamicType) -> PureSwiftClass
String(myvar2.dynamicType) -> Int
String(myvar3.dynamicType) -> String
String(Int.self)           -> Int
String((Int?).self         -> Optional<Int>
String(NSString.self)      -> NSString
String(Array<String>.self) -> Array<String>

Mise à jour pour Xcode 6.3 :

Vous pouvez utiliser le _stdlib_getDemangledTypeName() :

print( "TypeName0 = \(_stdlib_getDemangledTypeName(myvar0))")
print( "TypeName1 = \(_stdlib_getDemangledTypeName(myvar1))")
print( "TypeName2 = \(_stdlib_getDemangledTypeName(myvar2))")
print( "TypeName3 = \(_stdlib_getDemangledTypeName(myvar3))")

et j'obtiens ceci comme résultat :

TypeName0 = NSString
TypeName1 = __lldb_expr_26.PureSwiftClass
TypeName2 = Swift.Int
TypeName3 = Swift.String

Réponse originale :

Avant Xcode 6.3 _stdlib_getTypeName a obtenu le nom de type tronqué d'une variable. Entrée du blog d'Ewan Swick aide à déchiffrer ces chaînes de caractères :

par exemple _TtSi représente le système interne de Swift Int type.

Mike Ash a un excellent article de blog couvrant le même sujet. .

2 votes

Comment avez-vous trouvé _stdlib_getTypeName() ? Le REPL intégré n'existe plus, swift-ide-test n'existe pas non plus, et l'impression du module Swift par Xcode ne tient pas compte des éléments suivants _ -des valeurs préfixées.

10 votes

On dirait que je peux rechercher des symboles avec lldb assez facilement dans le repl. Il y a aussi _stdlib_getDemangledTypeName() y _stdlib_demangleName() .

0 votes

Je l'ai vu pour la première fois dans un symbol dump gist sur github. Je ne peux pas reconstituer lequel exactement car il y en avait tellement. Mais vous avez raison, un simple (lldb) image dump symtab libswiftCore.dylib donne le même résultat. BTW : Belle prise avec _stdlib_demangleName() !

46voto

akashivskyy Points 11508

Editar: Une nouvelle toString fonction a été introduit dans Swift 1.2 (Xcode 6.3) .

Vous pouvez maintenant imprimer le type démêlé de n'importe quel type en utilisant .self et toute instance utilisant .dynamicType :

struct Box<T> {}

toString("foo".dynamicType)            // Swift.String
toString([1, 23, 456].dynamicType)     // Swift.Array<Swift.Int>
toString((7 as NSNumber).dynamicType)  // __NSCFNumber

toString((Bool?).self)                 // Swift.Optional<Swift.Bool>
toString(Box<SinkOf<Character>>.self)  // __lldb_expr_1.Box<Swift.SinkOf<Swift.Character>>
toString(NSStream.self)                // NSStream

Essayez d'appeler YourClass.self y yourObject.dynamicType .

Référence : https://devforums.apple.com/thread/227425 .

2 votes

J'ai répondu à ce fil de discussion, mais je vais ajouter mon commentaire ici. Ces valeurs sont de type "Metatype", mais il ne semble pas y avoir de moyen facile de savoir quel type un objet Metatype représente, ce qui est ce que je recherche.

0 votes

Ils sont de type Metatype, et ce sont des classes. Ils représentent une classe. Je ne sais pas exactement quel est votre problème avec ça. someInstance.dynamicType.printClassName() imprimera le nom de la classe.

18 votes

La méthode printClassName() est juste une méthode d'exemple créée dans l'un des échantillons de la documentation, ce n'est pas un appel API auquel vous pouvez accéder.

30voto

Haiku Oezu Points 328

C'est ce que vous cherchez ?

println("\(object_getClassName(now))");

Il imprime "__NSDate"

UPDATE : Veuillez noter que cela ne semble plus fonctionner à partir de la Beta05.

2 votes

Ne fonctionne pas pour les classes rapides. Retourne "UnsafePointer(0x7FBB18D06DE0)".

4 votes

Cela ne fonctionne pas non plus pour les classes ObjC (du moins dans la Beta5), pour un NSManagedObject j'obtiens juste "Builtin.RawPointer = adresse".

23voto

Matt Hagen Points 91

Mon Xcode actuel est la version 6.0 (6A280e).

import Foundation

class Person { var name: String; init(name: String) { self.name = name }}
class Patient: Person {}
class Doctor: Person {}

var variables:[Any] = [
    5,
    7.5,
    true,
    "maple",
    Person(name:"Sarah"),
    Patient(name:"Pat"),
    Doctor(name:"Sandy")
]

for variable in variables {
    let typeLongName = _stdlib_getDemangledTypeName(variable)
    let tokens = split(typeLongName, { $0 == "." })
    if let typeName = tokens.last {
        println("Variable \(variable) is of Type \(typeName).")
    }
}

Sortie :

Variable 5 is of Type Int.
Variable 7.5 is of Type Double.
Variable true is of Type Bool.
Variable maple is of Type String.
Variable Swift001.Person is of Type Person.
Variable Swift001.Patient is of Type Patient.
Variable Swift001.Doctor is of Type Doctor.

1 votes

Bien, mais la question incluait aussi des optionnels, la sortie des optionnels est fixée dans Optional(...) donc votre code ne renverrait que Optional comme le Type. Il devrait également indiquer var optionalTestVar: Person? = Person(name:"Sarah") as Optional(Person) and var with Person ! as ImplicitlyUnwrappedOptional(Person)

17voto

Leandros Points 5916

Vous pouvez toujours accéder à la classe, par className (qui renvoie un String ).

Il existe en fait plusieurs façons d'obtenir la classe, par exemple classForArchiver , classForCoder , classForKeyedArchiver (tous les retours AnyClass! ).

On ne peut pas obtenir le type d'une primitive (une primitive est no une classe).

Exemple :

var ivar = [:]
ivar.className // __NSDictionaryI

var i = 1
i.className // error: 'Int' does not have a member named 'className'

Si vous voulez obtenir le type d'une primitive, vous devez utiliser bridgeToObjectiveC() . Exemple :

var i = 1
i.bridgeToObjectiveC().className // __NSCFNumber

0 votes

Je parie que c'est un primitif. Malheureusement, vous ne pouvez pas obtenir le type d'une primitive.

0 votes

Ces exemples ne semblent pas fonctionner dans la cour de récréation. J'obtiens l'erreur pour les primitives et les non-primitives.

0 votes

Essayer de import Cocoa .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X