问题
How to list all classes implementing a given protocol in Swift?
Say we have an example:
protocol Animal {
func speak()
}
class Cat:Animal {
func speak() {
print("meow")
}
}
class Dog: Animal {
func speak() {
print("Av Av!")
}
}
class Horse: Animal {
func speak() {
print("Hurrrr")
}
}
Here is my current (not compilable) approach:
func getClassesImplementingProtocol(p: Protocol) -> [AnyClass] {
let classes = objc_getClassList()
var ret = [AnyClass]()
for cls in classes {
if class_conformsToProtocol(cls, p) {
ret.append(cls)
}
}
return ret
}
func objc_getClassList() -> [AnyClass] {
let expectedClassCount = objc_getClassList(nil, 0)
let allClasses = UnsafeMutablePointer<AnyClass?>.alloc(Int(expectedClassCount))
let autoreleasingAllClasses = AutoreleasingUnsafeMutablePointer<AnyClass?>(allClasses)
let actualClassCount:Int32 = objc_getClassList(autoreleasingAllClasses, expectedClassCount)
var classes = [AnyClass]()
for i in 0 ..< actualClassCount {
if let currentClass: AnyClass = allClasses[Int(i)] {
classes.append(currentClass)
}
}
allClasses.dealloc(Int(expectedClassCount))
return classes
}
But when calling either
getClassesImplementingProtocol(Animal.Protocol)
or
getClassesImplementingProtocol(Animal)
or
getClassesImplementingProtocol(Animal.self)
results in Xcode error: cannot convert value of type (Animal.Protocol).Type to expected argument type 'Protocol'.
Did anyone manage get this working?
回答1:
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.
回答2:
In terms of speed, you can do it in a single for, and avoid having to iterate through all classes like so:
func getClassesConformingProtocol(p: Protocol)-> [AnyClass]{
let expectedClassCount = objc_getClassList(nil, 0)
let allClasses = UnsafeMutablePointer<AnyClass>.allocate(capacity: Int(expectedClassCount))
let autoreleasingAllClasses = AutoreleasingUnsafeMutablePointer<AnyClass>(allClasses)
let actualClassCount:Int32 = objc_getClassList(autoreleasingAllClasses, expectedClassCount)
var classes = [AnyClass]()
for i in 0 ..< actualClassCount {
let currentClass = allClasses[Int(i)]
if class_conformsToProtocol(currentClass, p) {
classes.append(currentClass)
}
}
return classes
}
来源:https://stackoverflow.com/questions/34415028/how-to-list-all-classes-conforming-to-protocol-in-swift