Swift支持reflection吗?

Swift支持reflection吗? 例如是否有像valueForKeyPath:setValue:forKeyPath:对于Swift对象?

实际上,它甚至有一个dynamictypes系统,像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的所有内省和dynamic都起作用。 这包括:

  • 向类请求方法和属性,调用方法或设置属性的能力。
  • 交换方法实现的能力。 (为所有实例添加function)。
  • 即时生成和分配新的子类的能力。 (给给定实例添加function)

这个function的一个缺点是支持Swift可选值types。 例如Int属性可以被枚举和修改,但是Int? 属性不能。 可选types可以使用reflect / MirrorType部分枚举,但仍未修改。

如果一个类没有扩展NSObject ,那么只有新的非常有限的(正在进行的)reflection工作(参见reflect / MirrorType),这增加了向实例询问其类和属性的有限能力,但是没有附加特性以上。

当不扩展NSObject或使用'@objc'指令时,Swift默认为基于静态和基于vtable的调度。 但是,这是更快的,因为在没有虚拟机的情况下不允许运行时方法拦截。 这个拦截是Cocoa的一个基本部分,对于下列types的function是必需的:

  • cocoa的优雅的财产观察员。 (财产观察员被烘烤到Swift语言)。
  • 无创地应用横切问题,如日志logging,事务pipe理(即面向方面编程)。
  • 代理,信息转发等

因此,build议使用Swift实现Cocoa / CocoaTouch应用程序中的类:

  • 从NSObject扩展。 Xcode中的新类对话框在这个方向上。
  • 如果dynamic调度的开销导致性能问题,则可以使用静态调度 – 例如,在调用具有非常小的体的方法的紧密循环中。

概要:

  • Swift的行为可以像C ++一样,具有快速的静态/虚表调度和有限的reflection。 这使得它适用于较低级别或性能密集型应用程序,但没有与C ++相关的复杂性,学习曲线或错误风险
  • 虽然Swift是一种编译语言,但方法调用的消息传递风格增加了现代语言(如Ruby和Python)中的内省和dynamic,就像Objective-C一样,但没有Objective-C的传统语法。

参考数据:方法调用的执行开销:

  • 静态:<1.1ns
  • vtable:〜1.1ns
  • dynamic:〜4.9ns

(实际性能取决于硬件,但比例将保持相似)。

另外,dynamic属性允许我们明确地指示Swift一个方法应该使用dynamic调度,因此将支持拦截。

 public dynamic func foobar() -> AnyObject { } 

该文档讲述了一个dynamictypes系统,主要是关于

TypedynamicType

请参阅元数据types(在语言参考中)

例:

 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的答案。 对于内置的属性,有一些简单的只读reflection,可能允许IDE检查对象内容。

目前看来,SwiftreflectionAPI对于苹果来说并不是一个高度优先的事情。 但除了@stevex 答案 ,标准库中还有另一个function可以帮助。

从beta 6开始, _stdlib_getTypeName获取variables的损坏types名称。 将其粘贴到一个空的操场上:

 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的博客文章有助于破译这些string:

例如_TtSi代表Swift的内部Inttypes。

Mike Ash有一篇很棒的博客文章,涵盖了同一主题 。

你可能要考虑使用toString()来代替。 它是公共的,和_stdlib_getTypeName()一样工作 ,不同之处在于它也适用于AnyClass ,例如在游乐场input

 class MyClass {} toString(MyClass.self) // evaluates to "__lldb_expr_49.MyClass"