ios Swift 支持反射吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24060667/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 00:31:37  来源:igfitidea点击:

Does Swift support reflection?

iosreflectionswift

提问by Khanh Nguyen

Does Swift support reflection? e.g. is there something like valueForKeyPath:and setValue:forKeyPath:for Swift objects?

Swift 支持反射吗?例如,有什么样valueForKeyPath:setValue:forKeyPath:对雨燕的对象?

Actually does it even have a dynamic type system, something like obj.classin Objective-C?

实际上它甚至有一个动态类型系统,就像obj.class在 Objective-C 中一样?

采纳答案by stevex

Looks like there's the start of some reflection support:

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

class Fruit {
    var name="Apple"
}

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

From mchambers gist, here: https://gist.github.com/mchambers/fb9da554898dae3e54f2

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

回答by Jasper Blues

If a class extends NSObject, then all of Objective-C's introspection and dynamism works. This includes:

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

  • The ability to ask a class about its methods and properties, and to invoke methods or set properties.
  • The ability to exchange method implementations. (add functionality to all instances).
  • The ability to generate and assign a new sub-class on the fly. (add functionality to a given instance)
  • 向类询问其方法和属性以及调用方法或设置属性的能力。
  • 交换方法实现的能力。(为所有实例添加功能)。
  • 动态生成和分配新子类的能力。(向给定实例添加功能)

One shortcoming of this functionality is support for Swift optional value types. For example Int properties can be enumerated and modified but Int? properties cannot. Optional types can be enumerated partially using reflect/MirrorType, but still not modified.

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

If a class does not extend NSObject, then only the new, very limited (and in progress?) reflection works (see reflect/MirrorType), which adds limited ability to ask a instance about its class and properties, but none of the additional features above.

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

When not extending NSObject, or using the '@objc' directive, Swift defaults to static- and vtable-based dispatch. This is faster, however, in the absence of a virtual machine does not allow runtime method interception. This interception is a fundamental part of Cocoa and is required for the following types of features:

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

  • Cocoa's elegant property observers. (Property observers are baked right in to the Swift language).
  • Non-invasively applying cross-cutting concerns like logging, transaction management (i.e Aspect Oriented Programming).
  • Proxies, message forwarding, etc.
  • Cocoa 优雅的属性观察者。(属性观察器直接融入 Swift 语言)。
  • 非侵入性地应用横切关注点,如日志记录、事务管理(即面向方面的编程)。
  • 代理、消息转发等

Therefore its recommended that clases in Cocoa/CocoaTouch applications implemented with Swift:

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

  • Extend from NSObject. The new class dialog in Xcode steers in this direction.
  • Where the overhead of of a dynamic dispatch leads to performance issues, then static dispatch can be used - in tight loops with calls to methods with very small bodies, for example.
  • 从 NSObject 扩展。Xcode 中的新类对话框朝着这个方向发展。
  • 如果动态调度的开销导致性能问题,那么可以使用静态调度——例如,在调用具有非常小的主体的方法的紧密循环中。

Summary:

概括:

  • Swift can behave like C++, with fast static/vtable dispatch and limited reflection. This makes it suitable for lower level or performance intensive applications, but without the complexity, learning curve or risk of error associated with C++
  • While Swift is a compiled language, the messaging style of method invocation adds the introspection and dynamism found in modern languages like Ruby and Python, just like Objective-C, but without Objective-C's legacy syntax.
  • Swift 可以像 C++ 一样运行,具有快速的静态/虚拟表调度和有限的反射。这使其适用于较低级别或性能密集型应用程序,但没有与 C++ 相关的复杂性、学习曲线或错误风险
  • 虽然 Swift 是一种编译语言,但方法调用的消息传递风格增加了 Ruby 和 Python 等现代语言中的内省和动态,就像 Objective-C 一样,但没有 Objective-C 的遗留语法。

Reference data: Execution overhead for method invocations:

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

  • static : < 1.1ns
  • vtable : ~ 1.1ns
  • dynamic : ~4.9ns
  • 静态:< 1.1ns
  • 虚拟表:~ 1.1ns
  • 动态:~4.9ns

(actual performance depends on hardware, but the ratios will remain similar).

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

Also, the dynamic attribute allows us to explicitly instruct Swift that a method should use dynamic dispatch, and will therefore support interception.

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

public dynamic func foobar() -> AnyObject {
}

回答by Sulthan

The documentation speaks about a dynamic type system, mainly about

该文档谈到了动态类型系统,主要是关于

Typeand dynamicType

TypedynamicType

See Metatype Type (in Language Reference)

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

Example:

例子:

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

var type = instance.dynamicType

println("Type: \(type)") //Unfortunately this prints only "Type: Metatype"

Now assuming TestObjectextends NSObject

现在假设TestObject扩展NSObject

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

if let testObject = instance as? TestObject {
    println("yes!") //prints "yes!"
}

Currently, there is no reflection implemented.

目前,没有实现反射。

EDIT:I was apparently wrong, see stevex's answer. There is some simple readonly reflection for properties build in, probably to allow IDEs to inspect object contents.

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

回答by Klaas

It seems that a Swift reflection API is not a high priority for Apple at the moment. But besides @stevex answerthere is another function in the standard library that helps.

目前看来,Swift 反射 API 并不是 Apple 的首要任务。但是除了@stevex 的回答之外,标准库中还有另一个功能可以提供帮助。

As of beta 6 _stdlib_getTypeNamegets the mangled type name of a variable. Paste this into an empty playground:

从 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))")

The output is:

输出是:

TypeName0 = NSString
TypeName1 = _TtC13__lldb_expr_014PureSwiftClass
TypeName2 = _TtSi
TypeName3 = _TtSS

Ewan Swick's blog entryhelps to decipher these strings:

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

e.g. _TtSistands for Swift's internal Inttype.

eg_TtSi代表 Swift 的内部Int类型。

Mike Ash has a great blog entry covering the same topic.

Mike Ash 有一篇很棒的博客条目,涵盖了相同的主题

回答by silkentrance

You might want to consider using toString()instead. It is public and works just the same as _stdlib_getTypeName()with the difference that it also works on AnyClass, e.g. in a Playground enter

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

class MyClass {}

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

回答by Hymany

No reflectkeyword in Swift 5, now you can use

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