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!
.
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 Types'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 .
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 .
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
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>"
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.
à 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"
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
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
j'ai eu de la chance avec:
let className = NSStringFromClass(obj.dynamicType)
Xcode 8 Swift 3.0 Type d'Utilisation(of:)
let className = "\(type(of: instance))"
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
dans Swift 3.0, vous pouvez utiliser type(of:)
, car le mot-clé dynamicType
a été supprimé.
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
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.
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.
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;
}
dans le dernier Xcode 6.3 avec Swift 1.2, c'est le seul moyen que j'ai trouvé:
if view.classForCoder.description() == "UISegment" {
...
}
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é.
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.
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"
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)")
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.
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'
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.
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.
Xcode 7.3.1, Swift 2.2:
String(instanceToPrint.self).componentsSeparatedByString(".").last
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")
}
version Swift 4:
print("\(type(of: self)) ,\(#function)")
// within a function of a class
Merci @Joshua Danse
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
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
}