在 Swift 中,你能在一个模块中找到所有遵守特定协议的类型吗? [英] In Swift, can you find all types in a module that adhere to a specific protocol?

查看:71
本文介绍了在 Swift 中,你能在一个模块中找到所有遵守特定协议的类型吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

protocol Animal{}协议车辆{}协议收藏{}狗类:动物{}类猫:动物,最喜欢的{}类汽车:车辆{}类自行车:车辆,最喜欢的{}

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

  • 自行车

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

解决方案

我不认为 Swift 目前有一个原生"(不依赖于 Objective-C 运行时)API 来进行这种反射.

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

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

protocol 最喜欢的:class {}

然后您可以使用objc_copyClassList:

导入基础协议动物{}协议车辆{}最喜欢的协议:class {}狗类:动物{}类猫:动物,最喜欢的 {}类汽车:车辆{}类自行车:车辆,最喜欢的 {}///使用包含 Obj-C 已知的所有元类的缓冲区调用给定的闭包///运行.缓冲区仅在闭包调用期间有效.func withAllClasses(_ body: (UnsafeBufferPointer) throws ->电阻) 重新抛出 ->R{变量计数:UInt32 = 0让 classListPtr = objc_copyClassList(&count)推迟 {自由(UnsafeMutableRawPointer(classListPtr))}让 classListBuffer = UnsafeBufferPointer(开始:classListPtr,计数:Int(count))返回尝试主体(classListBuffer)}//Swift 中的 .flatMap <4.1let classes = withAllClasses { $0.compactMap { $0 as?收藏夹.类型 } }打印(类)//[自行车,猫]

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

In Swift 4, is it possible to find all types within the current module which adhere to a specific protocol?

For instance, say I've defined this protocol and these classes:

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

class Dog : Animal{
}

class Cat : Animal, Favorite{
}

class Car : Vehicle{
}

class Bicycle : Vehicle, Favorite{
}

I want to find all types that implement Favorite. This can be easily done in C#, but I’m not sure if you can in Swift.

  • Cat
  • Bicycle

If it helps, I'm using Swift 4.

解决方案

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).

这篇关于在 Swift 中,你能在一个模块中找到所有遵守特定协议的类型吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆