In Swift, can you find all types in a module that adhere to a specific protocol?
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
).
Checking if Any.Type conforms to a protocol in Swift
To check the pure Swift code, you can do:
protocol MySwiftProtocol: AnyObject {
}
class MySwiftClass: MySwiftProtocol {
}
if MySwiftClass.self as? MySwiftProtocol.Type != nil {
print("conforms")
} else {
print("does not conform")
}
or more simply:
if MySwiftClass.self is MySwiftProtocol.Type {
How to list all classes conforming to protocol in Swift?
Since you're using the Objective-C runtime to get the type introspection you need to add @objc
to your code in this manner:
@objc protocol Animal {
func speak()
}
class Cat:Animal {
@objc func speak() {
print("meow")
}
}
class Dog: Animal {
@objc func speak() {
print("Av Av!")
}
}
class Horse: Animal {
@objc func speak() {
print("Hurrrr")
}
}
Note that this kind of type introspection might be very slow.
How do I get list of all classes conform to certain protocol in Xcode 4?
Use the Objective-C runtime functions.
objc_getClassList
to get the list ofClass
esclass_getSuperclass
or the-superclass
method to walk the superclass chainclass_conformsToProtocol
or the-conformsToProtocol:
method to check if a class conforms to a protocol
How do I determine what protocols a class conforms to in swift?
I don't believe you can do it without leaning on the Objective-C runtime. Import ObjectiveC
and use the class_copyProtocolList()
function.
Related Topics
Access Enum Associated Value as Optional
Ios8: Auto-Layout and Gradient
Should I Remove All Skspritenodes and Labels When I Switch from One Node to Another
How to Add Characters into Dateformatter
Swift:Program for Addition of 2 Numbers Using Closure
Xcode 7.1 Beta: Content of File Error
Swift 3 Errors with Additional Data
Does _Arraytype or _Arrayprotocol Not Available in Swift 3.1
When Two Optionals Are Assigned to an If Let Statement, Which One Gets Unwrapped? Swift Language
Nsmanagedobject Subclasses Duplicate Declaration
Label Showing Top of Screen Instead of Being on the Inputaccessoryview
Swift Tuple Has Unexpected Print Result
Getting the Time Remaining in the Time Interval of a Timer in Swift
Using @Viewbuilder to Create Views Which Support Multiple Children
How to Set Cadisplaylink in Swift with Weak Reference Between Target and Cadisplaylink Instance