斯威夫特是否支持反思?

Kha*_*yen 113 reflection ios swift

斯威夫特是否支持反思?例如,有什么样valueForKeyPath:setValue:forKeyPath:对雨燕的对象?

实际上它甚至有一个动态类型系统,类似于obj.classObjective-C?

ste*_*vex 85

看起来有一些反思支持的开始:

class Fruit {
    var name="Apple"
}

reflect(Fruit()).count         // 1
reflect(Fruit())[0].0          // "name"
reflect(Fruit())[0].1.summary  // "Apple"
Run Code Online (Sandbox Code Playgroud)

来自mchambers gist,在这里:https://gist.github.com/mchambers/fb9da554898dae3e54f2

  • 我要在WWDC的Swift实验室写这篇文章的作者.我想我会分享其余内容.正如大家所知,与我交谈过的工程师证实了reflect()函数的存在是为了支持Playground.但你仍然可以享受它的乐趣:)在这里我已经使用它破解了一个小模型序列化器.将它粘贴到游乐场并享受乐趣:https://gist.github.com/mchambers/67640d9c3e2bcffbb1e2 (11认同)
  • 它只适用于属性.没有方法反思. (7认同)
  • 好吧,我不认为这是一个真实的反映.首先,它是readonly.在我看来,这只是一个在Xcode中启用调试的黑客攻击.协议`镜像`实际上多次引用"IDE"这个词. (5认同)

Jas*_*ues 45

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

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

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

如果一个类没有扩展NSObject,那么只有新的,非常有限的(并且正在进行中)反射工作(参见reflect/MirrorType),这增加了向实例询问其类和属性的有限能力,但没有上述任何附加功能.

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

  • Cocoa优雅的财产观察员.(财产观察员直接使用Swift语言).
  • 非侵入性地应用横向关注问题,如日志记录,事务管理(即面向方面编程).
  • 代理,消息转发等

因此,它推荐使用Swift实现的Cocoa/CocoaTouch应用程序中的clases:

  • 从NSObject扩展.Xcode中的新类对话引导了这个方向.
  • 如果动态调度的开销导致性能问题,那么可以使用静态调度 - 例如,在调用具有非常小的主体的方法的紧密循环中.

摘要:

  • Swift的行为类似于C++,具有快速的静态/ vtable调度和有限的反射.这使其适用于较低级别或性能密集型应用程序,但没有与C++相关的复杂性,学习曲线或错误风险
  • 虽然Swift是一种编译语言,但方法调用的消息传递方式增加了现代语言(如Ruby和Python)中的内省和动态,就像Objective-C一样,但没有Objective-C的遗留语法.

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

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

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

此外,动态属性允许我们明确地指示Swift方法应该使用动态分派,因此将支持拦截.

public dynamic func foobar() -> AnyObject {
}
Run Code Online (Sandbox Code Playgroud)

  • 即使使用 Objective-C 技术,它似乎也不适用于可选的 Swift 类型。我建议在答案中注意这个限制,除非我错过了一个技巧。 (2认同)

Sul*_*han 8

文档讲的是动态类型系统,主要是关于

TypedynamicType

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

例:

var clazz = TestObject.self
var instance: TestObject = clazz()

var type = instance.dynamicType

println("Type: \(type)") //Unfortunately this prints only "Type: Metatype"
Run Code Online (Sandbox Code Playgroud)

现在假设TestObject延伸NSObject

var clazz: NSObject.Type = TestObject.self
var instance : NSObject = clazz()

if let testObject = instance as? TestObject {
    println("yes!") //prints "yes!"
}
Run Code Online (Sandbox Code Playgroud)

目前,没有实施反思.

编辑:我显然错了,看到史蒂夫斯的回答.对于内置属性,有一些简单的只读反射,可能允许IDE检查对象内容.


Kla*_*aas 6

似乎Swift反射API目前不是Apple的高优先级.但是,除了@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))")
Run Code Online (Sandbox Code Playgroud)

输出是:

TypeName0 = NSString
TypeName1 = _TtC13__lldb_expr_014PureSwiftClass
TypeName2 = _TtSi
TypeName3 = _TtSS
Run Code Online (Sandbox Code Playgroud)

Ewan Swick的博客文章有助于破译这些字符串:

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

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

  • 也可以使用`_stdlib_getDemangledTypeName` (5认同)

小智 5

您可能需要考虑使用toString().它是公共的,与_stdlib_getTypeName()的工作原理相同,区别在于它也适用于AnyClass,例如在Playground输入

class MyClass {}

toString(MyClass.self) // evaluates to "__lldb_expr_49.MyClass"
Run Code Online (Sandbox Code Playgroud)


Jac*_*cky 5

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)
}

Run Code Online (Sandbox Code Playgroud)