协议匹配器 (Protocol Matcher)

getClassesFor(_:)

列出编译器发现的所有符合指定协议的类类型。

func getClassesFor(_ yourprotocol: Protocol) -> [any AnyObject.Type]

参数 (Parameter): 协议 (Protocol)

返回值 (Returns): [any AnyObject.Type]

描述 (Description)

返回编译到您的应用程序构建中的,所有符合指定协议的类列表。 如果您在应用程序/包中提供一个协议,以及与任何实现该协议的类进行交互的方式,这将非常有用。 例如,您可以开发一种非常棒的分形查看方式,并为任何人提供一个 Fractal 协议来描述他们自己的分形。 无需修改任何代码,其他开发人员可以实现 Fractal 协议,您的代码可以检测到该类,并将其添加到查看的选择列表中。

如果在 Swift 中调用,为了正确识别预期的协议,必须在调用中将 self 添加到协议名称中。 例如,协议 Foo 必须作为 Foo.self 传递。
例如 (e.g.):

let matchingClassTypes = ProtocolMatcher().getClassesFor(Foo.self)

此外,Swift 协议定义必须用 @objc 标记,此函数才能识别该协议。例如 (e.g.):

@objc Foo { }

如果打算对返回值进行操作,则应将结果强制转换为特定类型。 使用上面的例子,这将是:

let matchingClassTypes = ProtocolMatcher().getClassesFor(Foo.self) as! [any Foo.Type]

不幸的是,在 Swift 包中无法围绕此函数添加更友好的 Swift 包装器,因为在撰写本文时,Swift 包不支持混合语言。

请注意,这与 Swift Mirror 方法不同,后者只能返回已实例化的类,而此方法将返回所有符合给定协议的类,无论是否已实例化。

注意 (Note)

为了实例化返回的类,协议必须要求一个 init 方法。 有关更多详细信息,请参见下面的示例。

完整的工作示例 (Fully worked example)

假设我们有一个名为 Secrets 的项目,其中包含以下代码:-

import ProtocolMatcher

// Define a protocol to test for
@objc protocol Food { init(); var secret: String {get} }

// and two conforming class definitions:
final class Baah : Food { init() {}; let secret = "applesauce" }
final class HumBug: Food { init() {}; let secret = "ketchup" }

final class FoodMatch {

  static func getFoodSecrets()  {
     let classesConforming = ProtocolMatcher().getClassesFor(Food.self) as! [any Food.Type]

     for classType in classesConforming {
        let className = "\(classType)"
        let classObject = classType.init()
        let secret = classObject.secret
        print("Found \(className) .. with a secret of \(secret)")
     }

  }
}

调用 FoodMatch.getFoodSecrets() 将打印

> Found Baah .. with a secret of applesauce
> Found HumBug .. with a secret of ketchup

https://github.com/disc0infern0/ProtocolMatcher 版权所有 2023 Andrew Cowley