In Swift, can you find all types in a module that adhere to a specific protocol?

走远了吗. 提交于 2019-12-06 01:03:08

I don't believe Swift currently has a 'native' (not dependant on the Objective-C runtime) API for doing this kind of reflection.

However, if you're on an Apple platform (and therefore have Obj-C interoperability), you could get a list of all classes registered with the Obj-C runtime, and then filter those that conform to a given protocol. This will work for Swift classes (even those that don't inherit from NSObject) because under the hood Swift classes are built on top of Obj-C classes (when there's Obj-C interop).

Because this will only work for classes (not structures or enumerations), you may want to restrict your protocol such that only classes can conform to it:

protocol Favorite : class {}

You can then do the following, using 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]

Here we're calling compactMap(_:) on the UnsafeBufferPointer to get back an array of metatypes that represent types conforming to Favorite (i.e those that can be cast to the existential metatype Favorite.Type).

No it is not possible to get names of classes inside a module.

You can count by your code, use extension protocol to count like below code :)

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()
  }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!