O Swift suporta reflexão? por exemplo, existe algo como valueForKeyPath:
e setValue:forKeyPath:
para objetos Swift?
Na verdade, ele ainda tem um sistema de tipo dinâmico, algo como obj.class
em Objective-C?
O Swift suporta reflexão? por exemplo, existe algo como valueForKeyPath:
e setValue:forKeyPath:
para objetos Swift?
Na verdade, ele ainda tem um sistema de tipo dinâmico, algo como obj.class
em Objective-C?
Respostas:
Parece que há o início de algum suporte de reflexão:
class Fruit {
var name="Apple"
}
reflect(Fruit()).count // 1
reflect(Fruit())[0].0 // "name"
reflect(Fruit())[0].1.summary // "Apple"
Do mchambers gist, aqui: https://gist.github.com/mchambers/fb9da554898dae3e54f2
Mirror
Na verdade, o protocolo cita a palavra IDE
várias vezes.
_stdlib_getTypeName
pode ajudar.
Se uma classe se estende NSObject
, então toda a introspecção e dinamismo de Objective-C funcionam. Isso inclui:
Uma lacuna dessa funcionalidade é o suporte para tipos de valor opcionais Swift. Por exemplo, as propriedades Int podem ser enumeradas e modificadas, mas Int? propriedades não podem. Tipos opcionais podem ser enumerados parcialmente usando reflect / MirrorType, mas ainda não modificados.
Se uma classe não se estende NSObject
, então apenas a nova reflexão muito limitada (e em andamento?) Funciona (consulte reflect / MirrorType), o que adiciona capacidade limitada de perguntar a uma instância sobre sua classe e propriedades, mas nenhum dos recursos adicionais acima .
Quando não está estendendo NSObject, ou usando a diretiva '@objc', o padrão do Swift é o envio estático e baseado em vtable. Isso é mais rápido, no entanto, na ausência de uma máquina virtual, não permite a interceptação do método de tempo de execução. Essa interceptação é uma parte fundamental do Cocoa e é necessária para os seguintes tipos de recursos:
Portanto, é recomendado que clases em aplicativos Cocoa / CocoaTouch implementados com Swift:
Resumo:
Dados de referência: sobrecarga de execução para invocações de método:
(o desempenho real depende do hardware, mas as relações permanecerão semelhantes).
Além disso, o atributo dinâmico nos permite instruir explicitamente ao Swift que um método deve usar despacho dinâmico e, portanto, oferecerá suporte à interceptação.
public dynamic func foobar() -> AnyObject {
}
A documentação fala sobre um sistema de tipo dinâmico, principalmente sobre
Type
e dynamicType
Consulte Tipo de Metatipo (na Referência da Linguagem)
Exemplo:
var clazz = TestObject.self
var instance: TestObject = clazz()
var type = instance.dynamicType
println("Type: \(type)") //Unfortunately this prints only "Type: Metatype"
Agora, supondo que TestObject
estendeNSObject
var clazz: NSObject.Type = TestObject.self
var instance : NSObject = clazz()
if let testObject = instance as? TestObject {
println("yes!") //prints "yes!"
}
Atualmente, não há reflexão implementada.
EDIT: Eu estava aparentemente errado, veja a resposta de stevex. Há uma reflexão simples somente leitura para propriedades incorporadas, provavelmente para permitir que os IDEs inspecionem o conteúdo do objeto.
Parece que uma API de reflexão Swift não é uma alta prioridade para a Apple no momento. Mas além da resposta de @stevex, há outra função na biblioteca padrão que ajuda.
A partir do beta 6 _stdlib_getTypeName
obtém o nome de tipo mutilado de uma variável. Cole isso em um playground vazio:
import Foundation
class PureSwiftClass {
}
var myvar0 = NSString() // Objective-C class
var myvar1 = PureSwiftClass()
var myvar2 = 42
var myvar3 = "Hans"
println( "TypeName0 = \(_stdlib_getTypeName(myvar0))")
println( "TypeName1 = \(_stdlib_getTypeName(myvar1))")
println( "TypeName2 = \(_stdlib_getTypeName(myvar2))")
println( "TypeName3 = \(_stdlib_getTypeName(myvar3))")
O resultado é:
TypeName0 = NSString
TypeName1 = _TtC13__lldb_expr_014PureSwiftClass
TypeName2 = _TtSi
TypeName3 = _TtSS
A entrada do blog de Ewan Swick ajuda a decifrar essas strings:
por exemplo, _TtSi
significa o Int
tipo interno do Swift .
Mike Ash tem um ótimo post no blog que cobre o mesmo tópico .
Você pode querer considerar o uso de toString () em vez disso. É público e funciona da mesma forma que _stdlib_getTypeName () com a diferença de que também funciona em AnyClass , por exemplo, em um Playground.
class MyClass {}
toString(MyClass.self) // evaluates to "__lldb_expr_49.MyClass"
Nenhuma reflect
palavra-chave no Swift 5, agora você pode usar
struct Person {
var name="name"
var age = 15
}
var me = Person()
var mirror = Mirror(reflecting: me)
for case let (label?, value) in mirror.children {
print (label, value)
}
json
desserialização