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

时间:2017-12-13 08:29:40

标签: swift reflection mirror

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

例如,假设我已经定义了这个协议和这些类:

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

class Dog : Animal{
}

class Cat : Animal, Favorite{
}

class Car : Vehicle{
}

class Bicycle : Vehicle, Favorite{
}

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

  • 自行车

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

3 个答案:

答案 0 :(得分:4)

我不相信斯威夫特目前有一个“本地人”。 (不依赖于Objective-C运行时)API来进行这种反射。

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

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

protocol Favorite : class {}

然后,您可以使用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]

我们在compactMap(_:)上调用UnsafeBufferPointer以获取表示符合Favorite的类型的元数据类型数组(即可以转换为存在元数据类型的元数据类型) Favorite.Type)。

答案 1 :(得分:0)

不能在模块中获取类的名称。

答案 2 :(得分:0)

您可以按照您的代码进行计数,使用扩展协议计算如下代码:)

protocol Animal{}
protocol Vehicle{}
protocol Favorite{
  func countImplement()
}

var totalImplement = 0
extension Favorite {
  func updateTotalImplement(){
    totalImplement += 1
  }
}

class Dog : Animal{
}

class Cat : Animal, Favorite{
   func countImplement(){
    this.updateTotalImplement()
  }
}

class Car : Vehicle{
}

class Bicycle : Vehicle, Favorite{
   func countImplement(){
    this.updateTotalImplement()
  }
}