Swift支持反思吗?例如是否有类似valueForKeyPath:
和setValue:forKeyPath:
的Swift对象?
实际上它甚至有一个动态类型系统,比如Objective-C中的obj.class
?
答案 0 :(得分:85)
看起来有一些反思支持的开始:
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
答案 1 :(得分:44)
如果一个类扩展NSObject
,那么Objective-C的所有内省和动态都会起作用。这包括:
此功能的一个缺点是支持Swift可选值类型。例如,Int属性可以枚举和修改,但Int?属性不能。可以使用reflect / MirrorType部分枚举可选类型,但仍未修改。
如果一个类没有扩展NSObject
,那么只有新的,非常有限的(并且正在进行中)反射工作(参见reflect / MirrorType),这增加了向实例询问其类和属性的有限能力,但没有上述附加功能。
当不延伸NSObject或使用' @ objc'指令,Swift默认为基于static和vtable的调度。然而,这更快,在没有虚拟机的情况下不允许运行时方法拦截。这种拦截是Cocoa的基本组成部分,是以下类型功能所必需的:
因此,它推荐使用Swift实现Cocoa / CocoaTouch应用程序中的clases:
<强>要点:强>
参考数据:方法调用的执行开销:
(实际性能取决于硬件,但比率将保持相似)。
此外,动态属性允许我们明确地指示Swift方法应该使用动态分派,因此将支持拦截。
public dynamic func foobar() -> AnyObject {
}
答案 2 :(得分:8)
文档讲述了一个动态类型系统,主要是关于
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检查对象内容。
答案 3 :(得分:6)
目前似乎Swift反射API并不是Apple的高优先级。但除了@stevex answer之外,标准库中还有另一个有用的功能。
从beta 6 _stdlib_getTypeName
获取变量的受损类型名称。将其粘贴到空的操场上:
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's blog entry有助于破译这些字符串:
e.g。 _TtSi
代表Swift的内部Int
类型。
答案 4 :(得分:5)
您可能需要考虑使用 toString()。它是公开的,与 _stdlib_getTypeName()的工作方式相同,区别在于它也适用于 AnyClass ,例如在游乐场输入
class MyClass {}
toString(MyClass.self) // evaluates to "__lldb_expr_49.MyClass"
答案 5 :(得分:1)
在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)
}