pass - swift class type
¿Cómo averiguas el tipo de un objeto(en Swift)? (11)
Cuando se trata de entender un programa, o en algunos casos, es útil poder averiguar qué tipo es algo. Sé que el depurador puede mostrarle cierta información de tipo y, por lo general, puede confiar en la inferencia de tipos para no especificar el tipo en esas situaciones, pero aún así, realmente me gustaría tener algo como el type()
de Python type()
dynamicType (ver esta pregunta )
Actualización: esto se ha modificado en una versión reciente de Swift, obj.dynamicType
ahora le proporciona una referencia al tipo y no a la instancia del tipo dinámico.
Este parece el más prometedor, pero hasta ahora no he podido averiguar el tipo real
class MyClass {
var count = 0
}
let mc = MyClass()
# update: this now evaluates as true
mc.dynamicType === MyClass.self
También intenté usar una referencia de clase para crear una instancia de un nuevo objeto, que funciona, pero extrañamente me dio un error diciendo que debo agregar un inicializador required
:
trabajos:
class MyClass {
var count = 0
required init() {
}
}
let myClass2 = MyClass.self
let mc2 = MyClass2()
Sin embargo, solo es un pequeño paso para descubrir realmente el tipo de un objeto determinado.
edición : he eliminado una cantidad sustancial de detalles irrelevantes ahora - mira el historial de edición si estás interesado :)
A partir de Xcode 6.0.1 (al menos, no estoy seguro de cuándo lo agregaron), su ejemplo original ahora funciona:
class MyClass {
var count = 0
}
let mc = MyClass()
mc.dynamicType === MyClass.self // returns `true`
Actualizar:
Para responder a la pregunta original, puede utilizar el tiempo de ejecución de Obj-C con objetos Swift sin problemas con éxito.
Intenta lo siguiente:
import Foundation
class MyClass { }
class SubClass: MyClass { }
let mc = MyClass()
let m2 = SubClass()
// Both of these return .Some("__lldb_expr_35.SubClass"), which is the fully mangled class name from the playground
String.fromCString(class_getName(m2.dynamicType))
String.fromCString(object_getClassName(m2))
// Returns .Some("__lldb_expr_42.MyClass")
String.fromCString(object_getClassName(mc))
Aquí hay 2 maneras en que recomiendo hacerlo:
if let thisShape = aShape as? Square
O:
aShape.isKindOfClass(Square)
Aquí hay un ejemplo detallado:
class Shape { }
class Square: Shape { }
class Circle: Shape { }
var aShape = Shape()
aShape = Square()
if let thisShape = aShape as? Square {
println("Its a square")
} else {
println("Its not a square")
}
if aShape.isKindOfClass(Square) {
println("Its a square")
} else {
println("Its not a square")
}
Depende del caso de uso. Pero supongamos que desea hacer algo útil con sus tipos de "variable". La instrucción Swift switch
es muy poderosa y puede ayudarlo a obtener los resultados que está buscando ...
let dd2 = ["x" : 9, "y" : "home9"]
let dds = dd2.filter {
let eIndex = "x"
let eValue:Any = 9
var r = false
switch eValue {
case let testString as String:
r = $1 == testString
case let testUInt as UInt:
r = $1 == testUInt
case let testInt as Int:
r = $1 == testInt
default:
r = false
}
return r && $0 == eIndex
}
En este caso, tenga un diccionario simple que contenga pares clave / valor que puedan ser UInt, Int o String. En el método .filter()
en el diccionario, debo asegurarme de probar los valores correctamente y solo probar una Cadena cuando es una cadena, etc. ¡La declaración de cambio hace que esto sea simple y seguro! Al asignar 9 a la variable de tipo Cualquiera, hace que el interruptor para Int ejecute. Intenta cambiarlo a:
let eValue:Any = "home9"
..y vuelve a intentarlo. Esta vez ejecuta el caso as String
.
El código "dynamicType.printClassName" proviene de un ejemplo en el libro Swift. No conozco ninguna forma de capturar directamente un nombre de clase personalizado, pero puede verificar un tipo de instancias usando la palabra clave "es" como se muestra a continuación. Este ejemplo también muestra cómo implementar una función de nombre de clase personalizada, si realmente desea el nombre de clase como una cadena.
class Shape {
class func className() -> String {
return "Shape"
}
}
class Square: Shape {
override class func className() -> String {
return "Square"
}
}
class Circle: Shape {
override class func className() -> String {
return "Circle"
}
}
func getShape() -> Shape {
return Square() // hardcoded for example
}
let newShape: Shape = getShape()
newShape is Square // true
newShape is Circle // false
newShape.dynamicType.className() // "Square"
newShape.dynamicType.className() == Square.className() // true
Tenga en cuenta que las subclases de NSObject ya implementan su propia función className. Si está trabajando con Cocoa, puede utilizar esta propiedad.
class MyObj: NSObject {
init() {
super.init()
println("My class is /(self.className)")
}
}
MyObj()
En Swift 2.0, la forma correcta de hacer este tipo de introspección de tipo sería con la estructura Mirror ,
let stringObject:String = "testing"
let stringArrayObject:[String] = ["one", "two"]
let viewObject = UIView()
let anyObject:Any = "testing"
let stringMirror = Mirror(reflecting: stringObject)
let stringArrayMirror = Mirror(reflecting: stringArrayObject)
let viewMirror = Mirror(reflecting: viewObject)
let anyMirror = Mirror(reflecting: anyObject)
Luego, para acceder al tipo en sí desde la estructura Mirror
, usaría la propiedad subjectType
así:
// Prints "String"
print(stringMirror.subjectType)
// Prints "Array<String>"
print(stringArrayMirror.subjectType)
// Prints "UIView"
print(viewMirror.subjectType)
// Prints "String"
print(anyMirror.subjectType)
Entonces puedes usar algo como esto:
if anyMirror.subjectType == String.self {
print("anyObject is a string!")
} else {
print("anyObject is not a string!")
}
Esto funciona en swift 3.
if unknownType is MyClass {
//unknownType is of class type MyClass
}
Para Swift 3.0
String(describing: <Class-Name>.self)
Para Swift 2.0 - 2.3
String(<Class-Name>)
Si recibe una advertencia de "siempre verdadero / falla", es posible que tenga que convertir a Cualquiera antes de usar.
(foo as Any) is SomeClass
Si simplemente necesita verificar si la variable es de tipo X, o si se ajusta a algún protocolo, entonces puede usar is
, o as?
como en el siguiente
var unknownTypeVariable = …
if unknownTypeVariable is <ClassName> {
//the variable is of type <ClassName>
} else {
//variable is not of type <ClassName>
}
Esto es equivalente a isKindOfClass
en Obj-C.
Y esto es equivalente a conformsToProtocol
, o isMemberOfClass
var unknownTypeVariable = …
if let myClass = unknownTypeVariable as? <ClassName or ProtocolName> {
//unknownTypeVarible is of type <ClassName or ProtocolName>
} else {
//unknownTypeVariable is not of type <ClassName or ProtocolName>
}
Versión Swift 3:
type(of: yourObject)
//: Playground - noun: a place where people can play
import UIKit
class A {
class func a() {
print("yeah")
}
func getInnerValue() {
self.dynamicType.a()
}
}
class B: A {
override class func a() {
print("yeah yeah")
}
}
B.a() // yeah yeah
A.a() // yeah
B().getInnerValue() // yeah yeah
A().getInnerValue() // yeah