Swift支持反射吗?


113

Swift支持反射吗?例如,是否有valueForKeyPath:setValue:forKeyPath:Swift对象类似的东西?

实际上,它甚至还具有动态类型系统,例如obj.class在Objective-C中吗?


1
我创建了一个帮助程序类以在Swift中进行反射。您可以在以下网址
Edwin Vermeer

2
他们已删除Swift 2.0中的反映。这就是我枚举属性和值的方式链接
mohacs

Answers:


85

看起来有些反射支持已经开始:

class Fruit {
    var name="Apple"
}

reflect(Fruit()).count         // 1
reflect(Fruit())[0].0          // "name"
reflect(Fruit())[0].1.summary  // "Apple"

从mchambers要点,在这里:https ://gist.github.com/mchambers/fb9da554898dae3e54f2


5
好吧,我不会认为这是真实的反映。一方面,它是只读的。在我看来,这只是在Xcode中启用调试的一种手段。协议Mirror实际上IDE多次引用该词。
苏珊(Sulthan)2014年

7
它仅适用于属性。没有方法反映。
Sulthan 2014年

11
要点的作者。我在WWDC的Swift实验室中写了这篇文章,以为我会分享其余的内容。大家都知道,与我交谈过的工程师们确认存在reflect()函数来支持Playground。但是您仍然可以享受它的乐趣:)在这里,我破解了一个使用它的小模型序列化程序。将其粘贴到操场上并玩得开心:gist.github.com/mchambers/67640d9c3e2bcffbb1e2
Marc Chambers

1
请查看答案stackoverflow.com/a/25345461/292145,以了解如何提供_stdlib_getTypeName帮助。
克拉斯

1
这里是一个类,会做基类和自选项目(非类型),并有NSCoding支持的反思和分析从和字典:github.com/evermeer/EVCloudKitDao/blob/master/AppMessage/...
埃德温·维米尔

44

如果一个类扩展了NSObject,那么Objective-C的所有内省和活力都会起作用。这包括:

  • 向类询问其方法和属性,以及调用方法或设置属性的能力。
  • 交换方法实现的能力。(向所有实例添加功能)。
  • 动态生成和分配新子类的能力。(向给定实例添加功能)

此功能的一个缺点是对Swift可选值类型的支持。例如,可以枚举和修改Int属性,但是Int?属性不能。可选类型可以使用reflect / MirrorType进行部分枚举,但仍不能修改。

如果一个类没有扩展NSObject,则只有新的,非常有限的(并且正在进行中?)反射起作用(请参见reflect / MirrorType),这增加了向实例询问有关其类和属性的能力,但是上面没有其他功能。

当不扩展NSObject或使用'@objc'指令时,Swift默认为基于静态和基于vtable的调度。但是,这更快,因为在没有虚拟机的情况下不允许运行时方法拦截。这种拦截是Cocoa的基本组成部分,并且是以下几种类型的功能所必需的:

  • 可可优雅的房地产观察家。(属性观察者会直接使用Swift语言)。
  • 非侵入性地应用横切关注点,例如日志记录,事务管理(即面向方面的编程)。
  • 代理,消息转发等

因此,建议使用Swift实施的Cocoa / CocoaTouch应用程序中的分类:

  • 从NSObject扩展。Xcode中的新类对话框将朝着这个方向发展。
  • 在动态调度的开销导致性能问题的地方,则可以使用静态调度-例如,在紧密循环中,调用具有很小主体的方法。

摘要:

  • Swift的行为类似于C ++,具有快速的静态/ vtable调度和有限的反射。这使其适用于较低级别或性能密集的应用程序,但没有C ++带来的复杂性,学习曲线或错误风险
  • 尽管Swift是一种编译语言,但是方法调用的消息传递样式增加了像Objective-C一样在Ruby和Python等现代语言中发现的内省性和动态性,但没有Objective-C的旧语法。

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

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

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

而且,dynamic属性允许我们显式指示Swift某个方法应使用动态调度,因此将支持拦截。

public dynamic func foobar() -> AnyObject {
}

2
即使使用Objective-C技术,它似乎也不适用于可选的Swift类型。我建议您在答案中注意此限制,除非我没有技巧。
whitneyland 2014年

8

该文档涉及动态类型系统,主要涉及

TypedynamicType

请参见元类型类型(在语言参考中)

例:

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!"
}

当前,没有实现反射。

编辑:我显然是错的,请参阅史蒂夫的答案。对于内置的属性有一些简单的只读反射,可能允许IDE检查对象内容。


6

目前,对于苹果而言,Swift反射API似乎并不是一个高优先级。但是,除了@stevex 答案之外,标准库中还有另一个函数可以提供帮助。

从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的博客条目有助于破译以下字符串:

例如_TtSi代表Swift的内部Int类型。

迈克·阿什(Mike Ash)在同一个主题的博客文章中非常出色


@aleclarson是的,这也很有用。
克拉斯2014年

1
那些私有API不是吗?如果使用,Apple会批准该应用程序吗?
爱德华多·科斯塔

@EduardoCosta是的,可以肯定。他们是私人的。我仅将它们用于调试构建。
克拉斯

这是Ewan Swick的博客文章的更新链接: eswick.com/2014/06/08/Inside-Swift
RenniePet

5

您可能要考虑使用toString()代替。它是公共的,并且与_stdlib_getTypeName()相同,不同之处在于它也适用于AnyClass,例如在Playground中

class MyClass {}

toString(MyClass.self) // evaluates to "__lldb_expr_49.MyClass"

1

reflectSwift 5中没有关键字,现在您可以使用

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反序列化
javadba
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.