How to list all classes conforming to protocol in Swift?

折月煮酒 提交于 2019-12-17 15:58:06

问题


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

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