¿Cómo imprimo el tipo o clase de una variable en Swift?

¿Hay alguna forma de imprimir el tipo de tiempo de ejecución de una variable rápidamente? Por ejemplo:

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 has no "description" method 

En el ejemplo anterior, estoy buscando una forma de mostrar que la variable “pronto” es de tipo ImplicitlyUnwrappedOptional , o al menos NSDate! .

Actualización septiembre de 2016

Swift 3.0: utilice el type(of:) , por ejemplo, type(of: someThing) (ya que se ha eliminado la palabra clave dynamicType )

Actualización de octubre de 2015 :

println los ejemplos a continuación a la nueva syntax de Swift 2.0 (por ejemplo, println fue reemplazado por print , toString() ahora es String() ).

De las notas de la versión de Xcode 6.3 :

@nschum señala en los comentarios que las notas de la versión de Xcode 6.3 muestran otra forma:

Los valores de tipo ahora se imprimen como el nombre completo de tipo demandado cuando se utiliza con println o interpolación de cadenas.

 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.self) -> \(Array.self)") 

Qué salidas:

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

Actualización para Xcode 6.3:

Puede usar _stdlib_getDemangledTypeName() :

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

y obtener esto como salida:

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

Respuesta original:

Antes de Xcode 6.3, _stdlib_getTypeName obtuvo el nombre de tipo mutilado de una variable. La entrada del blog de Ewan Swick ayuda a descifrar estas cadenas:

por ejemplo _TtSi significa tipo interno de Swift.

Mike Ash tiene una gran entrada de blog que cubre el mismo tema .

Editar: se ha introducido una nueva función toString en Swift 1.2 (Xcode 6.3) .

Ahora puede imprimir el tipo demangled de cualquier tipo usando .self y cualquier instancia usando .dynamicType :

 struct Box {} toString("foo".dynamicType) // Swift.String toString([1, 23, 456].dynamicType) // Swift.Array toString((7 as NSNumber).dynamicType) // __NSCFNumber toString((Bool?).self) // Swift.Optional toString(Box>.self) // __lldb_expr_1.Box> toString(NSStream.self) // NSStream 

Intenta llamar a YourClass.self y yourObject.dynamicType .

Referencia: https://devforums.apple.com/thread/227425 .

Es esto lo que estás buscando?

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

Imprime “__NSDate”

ACTUALIZACIÓN : tenga en cuenta que esto ya no parece funcionar a 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(describing: type(of: dictionary)) // "Dictionary" // Get full type as a string String(reflecting: type(of: string)) // "Swift.String" String(reflecting: type(of: stringArray)) // "Swift.Array" String(reflecting: type(of: dictionary)) // "Swift.Dictionary" 

Mi Xcode actual es la versión 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).") } } 

Salida:

 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. 

A partir de Xcode 6.3 con Swift 1.2, puede simplemente convertir los valores de tipo en el String completo demandado.

 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" println((Int, String).self) // "(Swift.Int, Swift.String)" println((String?()).dynamicType)// "Swift.Optional" println(NSDate) // "NSDate" println(NSDate.Type) // "NSDate.Type" println(WKWebView) // "WKWebView" toString(MyClass) // "[Module Name].MyClass" toString(MyClass().dynamicType) // "[Module Name].MyClass" 

Todavía puede acceder a la clase, a través de className (que devuelve una String ).

En realidad, hay varias maneras de obtener la clase, por ejemplo, classForCoder , classForKeyedArchiver , classForKeyedArchiver (todas devuelven AnyClass! ).

No puede obtener el tipo de primitiva (una primitiva no es una clase).

Ejemplo:

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

Si desea obtener el tipo de primitiva, debe usar bridgeToObjectiveC() . Ejemplo:

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

Puede usar reflect para obtener información sobre el objeto.
Por ejemplo, nombre de la clase de objeto:

 var classname = reflect (now) .summary

Tuve suerte con:

 let className = NSStringFromClass(obj.dynamicType) 

Xcode 8 Swift 3.0 use type (of 🙂

 let className = "\(type(of: instance))" 

En Xcode 8, Swift 3.0

Pasos:

1. Obtener el tipo:

Opción 1:

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

Opcion 2:

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

2. Convertir tipo a cadena:

 let string : String = "\(type)" //String 

En Swift 3.0, puede usar type(of:) , ya que se ha eliminado la palabra clave dynamicType .

SWIFT 3

Con la última versión de Swift 3 podemos obtener bonitas descripciones de los nombres de los tipos a través del inicializador de String . Como, por ejemplo, print(String(describing: type(of: object))) . Donde object puede ser una variable de instancia como array, un diccionario, un Int , un NSDate , una instancia de una clase personalizada, etc.

Aquí está mi respuesta completa: Obtener el nombre de clase del objeto como cadena en Swift

Esa pregunta busca una forma de obtener el nombre de clase de un objeto como cadena, pero también propuse otra forma de obtener el nombre de clase de una variable que no es la subclase de NSObject . Aquí está:

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

Hice una función estática que toma como parámetro un objeto de tipo Any y devuelve su nombre de clase como String :).

Probé esta función con algunas variables como:

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

y la salida fue:

  • diccionary es de tipo Dictionary
  • array es del tipo Array
  • numInt es del tipo Int
  • numFloat es del tipo CGFloat
  • numDouble es del tipo Double
  • classOne es del tipo: ClassOne
  • classTwo es de tipo: ClassTwo
  • ahora es de tipo: Fecha
  • lbl es de tipo: UILabel

Al usar Cocoa (no CocoaTouch), puede usar la propiedad className para objetos que son subclases de NSObject.

 println(now.className) 

Esta propiedad no está disponible para objetos Swift normales, que no son subclases de NSObject (y de hecho, no hay una identificación de raíz o tipo de objeto en Swift).

 class Person { var name: String? } var p = Person() println(person.className) // <- Compiler error 

En CocoaTouch, en este momento no hay forma de obtener una descripción de cadena del tipo de una variable determinada. Funcionalidad similar tampoco existe para tipos primitivos en Cocoa o CocoaTouch.

El Swift REPL puede imprimir un resumen de valores, incluido su tipo, por lo que es posible que esta manera de introspección sea posible a través de una API en el futuro.

EDITAR : dump(object) parece hacer el truco.

He intentado algunas de las otras respuestas aquí, pero el kilometraje parece muy bien en lo que es el objeto subyacente.

Sin embargo, encontré una forma de obtener el nombre de la clase Object-C para un objeto haciendo lo siguiente:

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

Aquí hay un ejemplo de cómo lo usarías:

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

En este caso, imprimirá NSDate en la consola.

Encontré esta solución que con suerte podría funcionar para otra persona. Creé un método de clase para acceder al valor. Tenga en cuenta que esto funcionará solo para la subclase NSObject. Pero al menos es una solución limpia y ordenada.

 class var className: String!{ let classString : String = NSStringFromClass(self.classForCoder()) return classString.componentsSeparatedByString(".").last; } 

En el último XCode 6.3 con Swift 1.2, esta es la única forma que encontré:

 if view.classForCoder.description() == "UISegment" { ... } 

En lldb a partir de beta 5, puede ver la clase de un objeto con el comando:

 fr v -dr shipDate 

que produce algo así como:

 (DBSalesOrderShipDate_DBSalesOrderShipDate_ *) shipDate = 0x7f859940 

El comando expandido significa algo así como:

Frame Variable (imprimir una variable de marco) -d run_target (expandir tipos dynamics)

Algo útil para saber es que el uso de “Variable de cuadro” para dar salida a los valores de las variables garantiza que no se ejecute ningún código.

Encontré una solución para las clases autodesarrolladas (o a las que tienes acceso).

Coloque la siguiente propiedad calculada dentro de la definición de clase de objetos:

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

Ahora puedes simplemente llamar el nombre de la clase en tu objeto así:

 myObject.className 

Tenga en cuenta que esto solo funcionará si la definición de su clase se realiza dentro de un archivo que se llame exactamente igual a la clase de la que desea el nombre.

Como suele ser el caso, la respuesta anterior debería hacerlo en la mayoría de los casos . Pero en algunos casos especiales, puede que necesites encontrar una solución diferente.


Si necesita el nombre de la clase dentro de la clase (archivo) en sí , simplemente puede usar esta línea:

 let className = __FILE__.lastPathComponent.stringByDeletingPathExtension 

Tal vez este método ayude a algunas personas por ahí.

En base a las respuestas y los comentarios de Klass y Kevin Ballard mencionados anteriormente, me gustaría ir con:

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

que se imprimirá:

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

Muchas de las respuestas aquí no funcionan con el último Swift (Xcode 7.1.1 al momento de escribir).

La forma actual de obtener la información es crear un Mirror e interrogarlo. Para el nombre de clase, es tan simple como:

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

También se puede obtener información adicional sobre el objeto desde el Mirror . Ver http://swiftdoc.org/v2.1/type/Mirror/ para más detalles.

La respuesta principal no tiene un ejemplo práctico de la nueva forma de hacer esto usando el type(of: Así que para ayudar a los novatos como yo, aquí hay un ejemplo de trabajo, tomado principalmente de los documentos de Apple aquí – 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' 

Parece que no hay una forma genérica de imprimir el tipo de nombre de un tipo de valor arbitrario. Como otros han notado, para instancias de clase puede imprimir value.className pero para valores primitivos parece que en tiempo de ejecución, la información de tipo ha desaparecido.

Por ejemplo, parece que no hay forma de escribir: 1.something() y salir de Int para cualquier valor de something . (Puede, como sugirió otra respuesta, usar i.bridgeToObjectiveC().className para darle una pista, pero __NSCFNumber no es en realidad el tipo de i – solo a qué se convertirá cuando cruce el límite de un Objective- Llamada de función C.)

Me encantaría que se demuestre que estaba equivocado, pero parece que la comprobación de tipos se hace en tiempo de comstackción, y al igual que C ++ (con RTTI desactivado), gran parte de la información de tipo se ha ido en el tiempo de ejecución.

No es exactamente lo que buscas, pero también puedes verificar el tipo de la variable en contra de los tipos de Swift de la siguiente manera:

 let object: AnyObject = 1 if object is Int { } else if object is String { } 

Por ejemplo.

Xcode 7.3.1, Swift 2.2:

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

Swift 3.0, Xcode 8

Con el siguiente código, puede solicitar una instancia para su clase. También puede comparar dos instancias, ya sea que tenga la misma clase.

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

Swift versión 4:

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

Gracias @Joshua Dance

Así es como obtiene una cadena de tipo de su objeto o Tipo que es consistente y tiene en cuenta a qué módulo pertenece o en qué anida la definición del objeto. Funciona en 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 

Esto también es útil cuando se comprueba si un objeto es un tipo de clase:

 if someObject is SomeClass { //someObject is a type of SomeClass }