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系统,主要是关于
Type
和dynamicType
请参阅元数据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的内部Int
types。
Mike Ash有一篇很棒的博客文章,涵盖了同一主题 。
你可能要考虑使用toString()来代替。 它是公共的,和_stdlib_getTypeName()一样工作 ,不同之处在于它也适用于AnyClass ,例如在游乐场input
class MyClass {} toString(MyClass.self) // evaluates to "__lldb_expr_49.MyClass"