在Swift中,您能否在模块中找到符合特定协议的所有类型?

Mar*_*eIV 3 reflection mirror swift

在Swift 4中,是否有可能在当前模块中找到符合特定协议的所有类型?

例如,假设我已经定义了此协议和以下类:

protocol Animal{}
protocol Vehicle{}
protocol Favorite{}

class Dog : Animal{
}

class Cat : Animal, Favorite{
}

class Car : Vehicle{
}

class Bicycle : Vehicle, Favorite{
}
Run Code Online (Sandbox Code Playgroud)

我想找到所有实现的类型Favorite。这可以在C#中轻松完成,但是我不确定是否可以在Swift中进行。

  • 自行车

如果有帮助,我正在使用Swift 4。

Ham*_*ish 6

我不认为Swift目前有一个“本机”(不依赖于Objective-C运行时)API来进行这种反射。

但是,如果您使用的是Apple平台(因此具有Obj-C互操作性),则可以获取在Obj-C运行时注册的所有的列表,然后过滤符合给定协议的类。这将适用于Swift类(甚至是那些不继承自的类NSObject),因为在底层,Swift类是建立在Obj-C类之上的(当有Obj-C互操作时)。

因为这仅适用于类(不适用于结构或枚举),所以您可能希望限制协议,以便只有类才能符合它:

protocol Favorite : class {}
Run Code Online (Sandbox Code Playgroud)

然后,您可以使用进行以下操作objc_copyClassList

import Foundation

protocol Animal {}
protocol Vehicle {}
protocol Favorite : class {}

class Dog : Animal {}
class Cat : Animal, Favorite {}
class Car : Vehicle {}
class Bicycle : Vehicle, Favorite {}

/// Invokes a given closure with a buffer containing all metaclasses known to the Obj-C
/// runtime. The buffer is only valid for the duration of the closure call.
func withAllClasses<R>(
  _ body: (UnsafeBufferPointer<AnyClass>) throws -> R
) rethrows -> R {

  var count: UInt32 = 0
  let classListPtr = objc_copyClassList(&count)
  defer {
    free(UnsafeMutableRawPointer(classListPtr))
  }
  let classListBuffer = UnsafeBufferPointer(
    start: classListPtr, count: Int(count)
  )

  return try body(classListBuffer)
}
//                               .flatMap in Swift < 4.1
let classes = withAllClasses { $0.compactMap { $0 as? Favorite.Type } }
print(classes) // [Bicycle, Cat]
Run Code Online (Sandbox Code Playgroud)

在此,我们呼吁compactMap(_:)UnsafeBufferPointer找回代表类型符合元类型的数组Favorite(即那些可以强制转换为生存元类型Favorite.Type)。