代码之家  ›  专栏  ›  技术社区  ›  Mark A. Donohoe

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

  •  5
  • Mark A. Donohoe  · 技术社区  · 6 年前

    在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 回复  |  直到 6 年前
        1
  •  9
  •   Hamish    6 年前

    我认为Swift目前没有一个“本机”(不依赖于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 ).

        2
  •  0
  •   Rahul Dasgupta    6 年前

    不,无法获取模块内的类名称。

        3
  •  -1
  •   Sua Le    6 年前

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

    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()
      }
    }