Swift是否支持反射?例如,是否存在类似于valueForKeyPath:
和setValue:forKeyPath:
用于Swift对象的功能?
实际上,它是否具有动态类型系统,类似于Objective-C中的obj.class
?
Swift是否支持反射?例如,是否存在类似于valueForKeyPath:
和setValue:forKeyPath:
用于Swift对象的功能?
实际上,它是否具有动态类型系统,类似于Objective-C中的obj.class
?
看起来开始有一些反射支持:
class Fruit {
var name="Apple"
}
reflect(Fruit()).count // 1
reflect(Fruit())[0].0 // "name"
reflect(Fruit())[0].1.summary // "Apple"
来自mchambers的gist,这里是:https://gist.github.com/mchambers/fb9da554898dae3e54f2
如果一个类继承 NSObject
,那么所有的 Objective-C 反射和动态性都能够使用。这包括:
这种功能的一个不足之处是对于 Swift 的可选值类型支持不够完善。例如,Int 属性可以被枚举和修改,但 Int? 属性则不能。可选类型可以使用 reflect/MirrorType 部分地进行枚举,但仍然不能被修改。
如果一个类没有继承 NSObject
,那么只有新的、非常有限的(正在进行中?)反射工作(参见 reflect/MirrorType),它增加了询问一个实例关于其类和属性的有限能力,但没有上述所有其他功能。
当不扩展 NSObject 或使用 '@objc' 指令时,Swift 默认使用基于静态分派和虚表的分派方式。这种方式更快,但是在没有虚拟机的情况下不允许运行时方法拦截。这种拦截是 Cocoa 的一个基本部分,需要以下类型的功能:
因此,推荐在使用 Swift 实现 Cocoa/CocoaTouch 应用程序中的类时:
摘要:
参考数据:方法调用的执行开销:
(实际性能取决于硬件,但比率将保持相似)。
此外,dynamic 属性允许我们明确指示 Swift 一个方法应该使用动态分派,并因此支持拦截。
public dynamic func foobar() -> AnyObject {
}
文档介绍了一种动态类型系统,主要涉及Type
和dynamicType
。
请参见Metatype Type (in Language Reference)。
示例:
var clazz = TestObject.self
var instance: TestObject = clazz()
var type = instance.dynamicType
println("Type: \(type)") //Unfortunately this prints only "Type: Metatype"
TestObject
继承自 NSObject
。var clazz: NSObject.Type = TestObject.self
var instance : NSObject = clazz()
if let testObject = instance as? TestObject {
println("yes!") //prints "yes!"
}
目前,尚未实现反射。
编辑:我显然是错了,请参见stevex的答案。已经构建了一些简单的只读属性反射,可能是为了允许IDE检查对象内容。
在Swift 5中没有reflect
关键字,现在您可以使用
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
反序列化。 - WestCoastProjects您可能会考虑使用toString()代替。它是公共的并且与_stdlib_getTypeName()完全相同,不同之处在于它还适用于AnyClass,例如在Playground中输入
class MyClass {}
toString(MyClass.self) // evaluates to "__lldb_expr_49.MyClass"
目前苹果似乎没有将Swift反射API作为高优先级任务。但是除了@stevex的答案之外,标准库中还有另一个函数可以帮助。
从beta 6版开始,_stdlib_getTypeName
可以获取变量的类型名称。将以下内容复制到空白playground中:
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))")
TypeName0 = NSString
TypeName1 = _TtC13__lldb_expr_014PureSwiftClass
TypeName2 = _TtSi
TypeName3 = _TtSS
Ewan Swick的博客文章有助于解密这些字符串:
例如,_TtSi
代表Swift的内部Int
类型。