Como você descobre o tipo de um object (no Swift)?

Ao tentar entender um programa, ou em alguns casos, é útil ser capaz de descobrir qual é o tipo de algo. Eu sei que o depurador pode mostrar-lhe algumas informações de tipo, e você geralmente pode confiar na inferência de tipos para fugir de não especificar o tipo nessas situações, mas ainda assim, eu realmente gostaria de ter algo como o type() do Python

dynamicType (veja esta pergunta )

Atualização: isso foi alterado em uma versão recente do Swift, obj.dynamicType agora fornece uma referência ao tipo e não à instância do tipo dynamic.

Este parece ser o mais promissor, mas até agora não consegui descobrir o tipo real

 class MyClass { var count = 0 } let mc = MyClass() # update: this now evaluates as true mc.dynamicType === MyClass.self 

Eu também tentei usar uma referência de class para instanciar um novo object, o que funciona, mas estranhamente me deu um erro dizendo que devo adicionar um inicializador required :

trabalho:

 class MyClass { var count = 0 required init() { } } let myClass2 = MyClass.self let mc2 = MyClass2() 

Ainda é apenas um pequeno passo para realmente descobrir o tipo de qualquer object dado

edit : removi um número substancial de detalhes agora irrelevantes – veja o histórico de edições se você estiver interessado 🙂

Versão Swift 3:

 type(of: yourObject) 

No Swift 2.0, a maneira correta de fazer esse tipo de introspecção seria com a estrutura 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) 

Então, para acessar o próprio tipo a partir da estrutura Mirror você usaria a propriedade subjectType forma:

  // Prints "String" print(stringMirror.subjectType) // Prints "Array" print(stringArrayMirror.subjectType) // Prints "UIView" print(viewMirror.subjectType) // Prints "String" print(anyMirror.subjectType) 

Você pode então usar algo assim:

  if anyMirror.subjectType == String.self { print("anyObject is a string!") } else { print("anyObject is not a string!") } 

O código “dynamicType.printClassName” é de um exemplo no livro Swift. Não tenho como saber diretamente um nome de class personalizado, mas você pode verificar um tipo de instância usando a palavra-chave “is”, conforme mostrado abaixo. Este exemplo também mostra como implementar uma function className personalizada, se você realmente quiser o nome da class como uma string.

 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 

Observe que as subclasss de NSObject já implementam sua própria function className. Se você está trabalhando com Cocoa, você pode simplesmente usar essa propriedade.

 class MyObj: NSObject { init() { super.init() println("My class is \(self.className)") } } MyObj() 

A partir do Xcode 6.0.1 (pelo menos, não tenho certeza quando eles o adicionaram), seu exemplo original agora funciona:

 class MyClass { var count = 0 } let mc = MyClass() mc.dynamicType === MyClass.self // returns `true` 

Atualizar:

Para responder a pergunta original, você pode realmente usar o tempo de execução Obj-C com objects Swift simples com sucesso.

Tente o seguinte:

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

Se você simplesmente precisa verificar se a variável é do tipo X, ou se está de acordo com algum protocolo, então você pode usar is , ou as? como no seguinte:

 var unknownTypeVariable = … if unknownTypeVariable is  { //the variable is of type  } else { //variable is not of type  } 

Isso é equivalente a isKindOfClass em Obj-C.

E isso é equivalente a isMemberOfClass ou isMemberOfClass

 var unknownTypeVariable = … if let myClass = unknownTypeVariable as?  { //unknownTypeVarible is of type  } else { //unknownTypeVariable is not of type  } 

Isso funciona em rápida 3

 if unknownType is MyClass { //unknownType is of class type MyClass } 

Aqui estão duas maneiras que eu recomendo fazer isso:

 if let thisShape = aShape as? Square 

Ou:

 aShape.isKindOfClass(Square) 

Aqui está um exemplo detalhado:

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

Para o Swift 3.0

 String(describing: .self) 

Para Swift 2.0 – 2.3

 String() 

Depende do caso de uso. Mas vamos supor que você queira fazer algo útil com seus tipos de “variables”. A instrução swift switch é muito poderosa e pode ajudá-lo a obter os resultados que procura …

  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 } 

Nesse caso, tenha um dictionary simples que contenha pares de chave / valor que possam ser UInt, Int ou String. No método .filter() do dictionary, eu preciso ter certeza de que eu testei os valores corretamente e testei apenas uma String quando é uma string, etc. A instrução switch torna isso simples e seguro! Atribuindo 9 à variável do tipo Any, faz a mudança para Int executar. Tente alterá-lo para:

  let eValue:Any = "home9" 

..e tente novamente. Desta vez, ele executa o caso as String .

Se você receber um aviso de “sempre verdadeiro / falhar”, pode ser necessário transmitir para Qualquer um antes de usar

 (foo as Any) is SomeClass 
 //: 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") } } Ba() // yeah yeah Aa() // yeah B().getInnerValue() // yeah yeah A().getInnerValue() // yeah