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

y a-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! .

299
demandé sur emlai 2014-06-03 06:24:42

30 réponses

Mise À Jour Septembre 2016

Swift 3.0: utiliser type(of:) , p.ex. type(of: someThing) (le mot-clé dynamicType ayant été supprimé)

Mise À Jour Octobre 2015 :

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

de le Xcode 6.3 notes de version :

@nschum souligne dans les commentaires que le Xcode 6.3 notes de version montrent une autre voie:

Les valeurs de Type

s'impriment maintenant en tant que nom de type démangulé complet lorsqu'il est utilisé avec interpolation println ou string.

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

qui produit:

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 obtenez ceci en sortie:

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

réponse originale:

avant Xcode 6.3 _stdlib_getTypeName obtenu le nom de type mutilé d'une variable. Ewan Swick entrée de blog de aide à déchiffrer ces chaînes:

e.g. _TtSi signifie "1519140920 de type".

Mike Ash a une grande entrée de blog couvrant le même sujet .

334
répondu Klaas 2016-12-18 19:15:42

modifier: une nouvelle toString fonction a été introduite dans Swift 1.2 (Xcode 6.3) .

vous pouvez maintenant imprimer le type démangulé de n'importe quel type en utilisant .self et n'importe quelle instance en 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 et yourObject.dynamicType .

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

45
répondu akashivskyy 2015-04-22 22:43:35

c'est ce que vous cherchez?

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

imprime "__NSDate"

mise à jour : veuillez noter que cela ne semble plus fonctionner à partir de Beta05

30
répondu Haiku Oezu 2014-08-20 11:36:27

Swift 3.0

let string = "Hello"
let stringArray = ["one", "two"]
let dictionary = ["key": 2]

print(type(of: string)) // "String"

// Get type name as a string
String(describing: type(of: string)) // "String"
String(describing: type(of: stringArray)) // "Array<String>"
String(describing: type(of: dictionary)) // "Dictionary<String, Int>"

// Get full type as a string
String(reflecting: type(of: string)) // "Swift.String"
String(reflecting: type(of: stringArray)) // "Swift.Array<Swift.String>"
String(reflecting: type(of: dictionary)) // "Swift.Dictionary<Swift.String, Swift.Int>"
27
répondu Evgenii 2017-01-16 06:11:03

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, { "151900920" == "." })
    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.
23
répondu Matt Hagen 2014-09-08 17:45:01

à partir de Xcode 6.3 avec Swift 1.2, vous pouvez simplement convertir les valeurs de type dans le String démangulé complet .

toString(Int)                   // "Swift.Int"
toString(Int.Type)              // "Swift.Int.Type"
toString((10).dynamicType)      // "Swift.Int"
println(Bool.self)              // "Swift.Bool"
println([UTF8].self)            // "Swift.Array<Swift.UTF8>"
println((Int, String).self)     // "(Swift.Int, Swift.String)"
println((String?()).dynamicType)// "Swift.Optional<Swift.String>"
println(NSDate)                 // "NSDate"
println(NSDate.Type)            // "NSDate.Type"
println(WKWebView)              // "WKWebView"
toString(MyClass)               // "[Module Name].MyClass"
toString(MyClass().dynamicType) // "[Module Name].MyClass"
18
répondu kiding 2015-02-10 05:42:36

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

Il y a en fait plusieurs façons d'obtenir de la classe, par exemple classForArchiver , classForCoder , classForKeyedArchiver (tout retour de AnyClass! ).

vous ne pouvez pas obtenir le type d'une primitive (une primitive est pas 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 de un primitif, vous devez utiliser bridgeToObjectiveC() . Exemple:

var i = 1
i.bridgeToObjectiveC().className // __NSCFNumber
17
répondu Leandros 2014-06-03 02:35:59

vous pouvez utiliser reflect pour obtenir des informations sur l'objet.

Par exemple nom de la classe de l'objet:

var classname = reflect(now).summary
16
répondu Stan 2014-08-15 12:27:53

j'ai eu de la chance avec:

let className = NSStringFromClass(obj.dynamicType)
13
répondu mxcl 2014-09-07 20:58:30

Xcode 8 Swift 3.0 Type d'Utilisation(of:)

let className = "\(type(of: instance))"
11
répondu Hari Kunwar 2016-09-19 19:10:25

Dans Le Xcode 8, Swift 3.0

Suit:

1. Obtenir le Type:

Option 1:

let type : Type = MyClass.self  //Determines Type from Class

Option 2:

let type : Type = type(of:self) //Determines Type from self

2. Convertir le Type en chaîne de caractères:

let string : String = "\(type)" //String
10
répondu user1046037 2016-10-09 12:24:32

dans Swift 3.0, vous pouvez utiliser type(of:) , car le mot-clé dynamicType a été supprimé.

8
répondu BrunoSerrano 2016-09-17 06:07:07

SWIFT 3

avec la dernière version de Swift 3, Nous pouvons obtenir de jolies descriptions des noms de type à travers l'initialiseur String . Comme, par exemple print(String(describing: type(of: object))) . Où object peut être une variable d'instance comme tableau, un dictionnaire, un Int , un NSDate , une instance d'une classe personnalisée, etc.

Voici ma réponse complète: Obtenir le nom de la classe de l'objet comme une chaîne de caractères dans les messages Swift

cette question est à la recherche d'un moyen d'obtenir le nom de classe d'un objet en tant que chaîne, mais, aussi j'ai proposé une autre façon d'obtenir le nom de classe d'une variable qui n'est pas la sous-classe de NSObject . Le voici:

class Utility{
    class func classNameAsString(obj: Any) -> String {
        //prints more readable results for dictionaries, arrays, Int, etc
        return String(describing: type(of: obj))
    }
}

j'ai fait une fonction statique qui prend comme paramètre un objet de type Any et renvoie son nom de classe comme String :).

j'ai testé cette fonction avec quelques variables comme:

    let diccionary: [String: CGFloat] = [:]
    let array: [Int] = []
    let numInt = 9
    let numFloat: CGFloat = 3.0
    let numDouble: Double = 1.0
    let classOne = ClassOne()
    let classTwo: ClassTwo? = ClassTwo()
    let now = NSDate()
    let lbl = UILabel()

et la sortie était:

  • diccionary est de type Dictionnaire
  • tableau est de type Array
  • numInt est de type Int
  • numFloat is of type CGFloat
  • numDouble est de type Double
  • classOne est de type: ClassOne
  • classTwo est de type: ClassTwo
  • est maintenant de type: Date
  • lbl est de type: UILabel
6
répondu mauricioconde 2017-05-23 12:10:29

lorsque vous utilisez Cocoa (pas CocoaTouch), vous pouvez utiliser la propriété className pour les objets qui sont des sous-classes de NSObject.

println(now.className)

cette propriété n'est pas disponible pour les objets Swift normaux, qui ne sont pas des sous-classes de NSObject (et en fait, il n'y a pas d'id racine ou de type d'objet dans Swift).

class Person {
    var name: String?
}

var p = Person()
println(person.className) // <- Compiler error

Dans CocoaTouch, à ce moment il n'y a pas un moyen d'obtenir une chaîne de description du type d'une variable donnée. Similaire la fonctionnalité n'existe pas non plus pour les types primitifs dans Cocoa ou CocoaTouch.

la Swift REPL est capable d'imprimer un résumé des valeurs incluant son type, il est donc possible que cette manière d'introspection soit possible via une API à l'avenir.

MODIFIER : dump(object) semble faire l'affaire.

4
répondu Matt Bridges 2014-06-19 12:58:01

j'ai essayé quelques-unes des autres réponses ici, mais milage semble très sur ce qu'est l'objet sous-jacent.

cependant j'ai trouvé un moyen d'obtenir le nom de classe objet-C pour un objet en faisant ce qui suit:

now?.superclass as AnyObject! //replace now with the object you are trying to get the class name for

voici un exemple d'utilisation:

let now = NSDate()
println("what is this = \(now?.superclass as AnyObject!)")

dans ce cas, il imprimera NSDate dans la console.

4
répondu James Jones 2014-09-16 01:31:25

j'ai trouvé cette solution qui, je l'espère pourraient travailler pour quelqu'un d'autre. J'ai créé une méthode de classe pour accéder à la valeur. Veuillez garder à l'esprit que cela ne fonctionnera que pour la sous-classe NSObject. Mais au moins est une solution propre et ordonnée.

class var className: String!{
    let classString : String = NSStringFromClass(self.classForCoder())
    return classString.componentsSeparatedByString(".").last;
}
4
répondu DennyLou 2015-02-07 03:20:35

dans le dernier Xcode 6.3 avec Swift 1.2, c'est le seul moyen que j'ai trouvé:

if view.classForCoder.description() == "UISegment" {
    ...
}
4
répondu Joel Kopelioff 2015-04-09 02:07:30

dans lldb à partir de beta 5, vous pouvez voir la classe d'un objet avec la commande:

fr v -d r shipDate

qui produit quelque chose comme:

(DBSalesOrderShipDate_DBSalesOrderShipDate_ *) shipDate = 0x7f859940

la commande expanded out signifie quelque chose comme:

Frame Variable (imprimer une image variable) -d run_target (élargir les types de dynamiques)

il est utile de savoir que l'utilisation de" Frame Variable " pour produire des valeurs variables garantit qu'aucun code n'est exécuté.

3
répondu Kendall Helmstetter Gelner 2014-08-15 20:41:40

j'ai trouvé une solution pour les classes auto-développées (ou celles auxquelles vous avez accès).

inscrivez biens calculés dans la définition de votre catégorie d'objets:

var className: String? {
    return __FILE__.lastPathComponent.stringByDeletingPathExtension
}

Maintenant, vous pouvez simplement appeler le nom de classe sur votre objet comme suit:

myObject.className

s'il vous Plaît noter que ce sera ne fonctionne que si votre définition de classe est faite dans les un fichier qui s'appelle exactement comme la classe dont vous voulez le nom.

comme ceci est communément le cas la réponse ci-dessus devrait le faire pour la plupart des cas . Mais dans certains cas spéciaux, vous pourriez avoir besoin de trouver une autre solution.


si vous avez besoin du nom de classe dans la classe (file) elle-même vous pouvez simplement utiliser cette ligne:

let className = __FILE__.lastPathComponent.stringByDeletingPathExtension

Peut-être que cette méthode aide certaines personnes là-bas.

3
répondu Dschee 2014-12-18 00:20:16

basé sur les réponses et les commentaires donnés par Klass et Kevin Ballard ci-dessus, je dirais:

println(_stdlib_getDemangledTypeName(now).componentsSeparatedByString(".").last!)
println(_stdlib_getDemangledTypeName(soon).componentsSeparatedByString(".").last!)
println(_stdlib_getDemangledTypeName(soon?).componentsSeparatedByString(".").last!)
println(_stdlib_getDemangledTypeName(soon!).componentsSeparatedByString(".").last!)

println(_stdlib_getDemangledTypeName(myvar0).componentsSeparatedByString(".").last!)
println(_stdlib_getDemangledTypeName(myvar1).componentsSeparatedByString(".").last!)
println(_stdlib_getDemangledTypeName(myvar2).componentsSeparatedByString(".").last!)
println(_stdlib_getDemangledTypeName(myvar3).componentsSeparatedByString(".").last!)

qui imprimera:

"NSDate"
"ImplicitlyUnwrappedOptional"
"Optional"
"NSDate"

"NSString"
"PureSwiftClass"
"Int"
"Double"
3
répondu Vince O'Sullivan 2015-01-01 12:15:43
let i: Int = 20


  func getTypeName(v: Any) -> String {
    let fullName = _stdlib_demangleName(_stdlib_getTypeName(i))
    if let range = fullName.rangeOfString(".") {
        return fullName.substringFromIndex(range.endIndex)
    }
    return fullName
}

println("Var type is \(getTypeName(i)) = \(i)")
3
répondu Alex Burla 2015-01-22 23:18:58

beaucoup de réponses ici ne fonctionnent pas avec le dernier Swift (Xcode 7.1.1 au moment de la rédaction).

la façon actuelle d'obtenir l'information est de créer un Mirror et d'interroger cela. Pour le nom de classe c'est aussi simple que:

let mirror = Mirror(reflecting: instanceToInspect)
let classname:String = mirror.description

des informations supplémentaires sur l'objet peuvent également être extraites du Mirror . Voir http://swiftdoc.org/v2.1/type/Mirror/ pour plus de détails.

3
répondu Joseph Lord 2015-11-11 17:12:55

La première réponse n'est pas un exemple de travail de la nouvelle façon de faire cela à l'aide de type(of: . Donc, pour aider les débutants comme moi, voici un exemple de travail, pris la plupart du temps de Docs D'Apple ici - https://developer.apple.com/documentation/swift/2885064-type

doubleNum = 30.1

func printInfo(_ value: Any) {
    let varType = type(of: value)
    print("'\(value)' of type '\(varType)'")
}

printInfo(doubleNum)
//'30.1' of type 'Double'
3
répondu Joshua Dance 2017-09-06 05:17:05

il ne semble pas y avoir de façon générique pour imprimer le nom de type d'un type de valeur arbitraire. Comme d'autres l'ont noté, pour class instances, vous pouvez imprimer value.className mais pour les valeurs primitives, il apparaît que lors de l'exécution, l'information de type est disparu.

par exemple, il semble qu'il n'y ait aucun moyen de taper: 1.something() et de sortir Int pour n'importe quelle valeur de something . (Vous pouvez, comme une autre réponse suggérée, utiliser i.bridgeToObjectiveC().className donnez-vous un indice, mais __NSCFNumber est pas en fait le type de i -- exactement ce à quoi il sera converti quand il franchira la limite D'un appel de fonction objectif-C.)

je serais heureux d'être prouvé faux, mais il semble que la vérification de type est tout fait au moment de la compilation, et comme C++ (avec RTTI désactivé) la plupart des informations de type a disparu à l'exécution.

2
répondu ipmcc 2014-06-03 20:03:56

pas exactement ce que vous recherchez, mais vous pouvez également vérifier le type de la variable par rapport aux types Swift comme so:

let object: AnyObject = 1

if object is Int {
}
else if object is String {
}

par exemple.

1
répondu PersuitOfPerfection 2015-04-22 11:59:03

Xcode 7.3.1, Swift 2.2:

String(instanceToPrint.self).componentsSeparatedByString(".").last

1
répondu leanne 2016-06-24 22:24:18

Swift 3.0, Xcode 8

avec le code suivant vous pouvez demander une instance pour sa classe. Vous pouvez également comparer deux instances, ayant la même classe.

// CREATE pure SWIFT class
class MySwiftClass {
    var someString : String = "default"
    var someInt    : Int = 5
}

// CREATE instances
let firstInstance = MySwiftClass()
let secondInstance = MySwiftClass()
secondInstance.someString = "Donald"
secondInstance.someInt = 24

// INSPECT instances
if type(of: firstInstance) === MySwiftClass.self {
    print("SUCCESS with ===")
} else {
    print("PROBLEM with ===")
}

if type(of: firstInstance) == MySwiftClass.self {
    print("SUCCESS with ==")
} else {
    print("PROBLEM with ==")
}

// COMPARE CLASS OF TWO INSTANCES
if type(of: firstInstance) === type(of: secondInstance) {
    print("instances have equal class")
} else {
    print("instances have NOT equal class")
}
1
répondu LukeSideWalker 2017-02-14 06:46:31

version Swift 4:

print("\(type(of: self)) ,\(#function)")
// within a function of a class

Merci @Joshua Danse

1
répondu dengApro 2018-04-27 03:15:58

C'est ainsi que vous obtenez une chaîne de caractères de votre objet ou type qui est compatible et tient compte de laquelle module la définition de l'objet appartient Ou est imbriquée. Travaille à Swift 4.x.

@inline(__always) func typeString(for _type: Any.Type) -> String {
    return String(reflecting: type(of: _type))
}

@inline(__always) func typeString(for object: Any) -> String {
    return String(reflecting: type(of: type(of: object)))
}

struct Lol {
    struct Kek {}
}

// if you run this in playground the results will be something like
typeString(for: Lol.self)    //    __lldb_expr_74.Lol.Type
typeString(for: Lol())       //    __lldb_expr_74.Lol.Type
typeString(for: Lol.Kek.self)//    __lldb_expr_74.Lol.Kek.Type
typeString(for: Lol.Kek())   //    __lldb_expr_74.Lol.Kek.Type
1
répondu Igor Muzyka 2018-08-07 22:21:39

c'est aussi pratique pour vérifier si un objet est un type d'une classe:

if someObject is SomeClass {
    //someObject is a type of SomeClass
}
0
répondu Nam 2017-01-19 10:25:58