如何在 Swift 中使用反射获取所有 class 初始化程序

How to get all class initializers using reflection in Swift

我正在尝试从 Swift 中的 class 获取初始化程序的所有签名。初始化器可以镜像,我可以找到如下代码的签名。

enum MessageType {
    case say
    case shout
    case wisper
}

class Message {
    var text = ""
    var type : MessageType = .say
    init(text: String, type: MessageType) {
        self.type = type
        self.text = text
    }
    init(text: String) {
        self.text = text
    }
}

let firstInit = Message.init(text:)
let secondInit = Message.init(text:type:)

let firstMirror = Mirror(reflecting: firstInit)
let secondMirror = Mirror(reflecting: secondInit)

print(firstMirror.subjectType)
// (String) -> Message

print(secondMirror.subjectType)
// ((String, MessageType)) -> Message

但是,此代码需要指定 init,我想查找它。我期望的是如下所示:

let mirror = Mirror(reflecting: Message)

let inits = mirror.initializers
// something like [Message.init(text:), Message.init(text:type:)] as [Any]

for method in inits {
    let mirror = Mirror(reflecting: method)
    print(method.subjectType)
}

如何使用 Mirror 从 class 获取所有 init 初始化器?

Swift 中的 Mirror 结构提供了一些运行时内省功能,但对于默认情况,这些功能关注的是被反射的实例,而不是该实例的类型。来自 language reference for Mirror:

Mirror

Representation of the sub-structure and optional “display style” of any arbitrary subject instance.

Overview

Describes the parts—such as stored properties, collection elements, tuple elements, or the active enumeration case—that make up a particular instance. May also supply a “display style” property that suggests how this structure might be rendered.

您可以通过遵守 CustomReflectable 协议为您 Message 类型实现自定义镜像。然而,以列出可用初始化程序的单一目的实现自定义镜像,仍然需要手动将初始化程序的信息提供给自定义镜像的实现。

例如:

extension Message: CustomReflectable {
    var customMirror: Mirror {
        let children = DictionaryLiteral<String, Any>(dictionaryLiteral:
            ("init(text:)", type(of: Message.init(text:))),
            ("init(text:type:)", type(of: Message.init(text:type:))))

        return Mirror.init(Message.self, children: children,
                           displayStyle: .class)
    }
}

// using your custom mirror
let myMessage = Message(text: "foo")
for case (let label?, let value) in Mirror(reflecting: myMessage).children {
    print("\(label), \(value)")
} /* init(text:), (String) -> Message
     init(text:type:), ((String, MessageType)) -> Message */

尽管如此,这种手动实施要求可能会违背练习的目的。还要注意,反射仍然必须在实例而不是类型本身上执行(因此可能更容易简单地实现一个直接将初始化器描述为 static 类型 属性 的字典;但是这个的手动形式实施破坏了它的大部分价值)。