Как перечислить все классы, соответствующие протоколу в Swift?

Как перечислить все классы, реализующие данный протокол в Swift?

Скажем, у нас есть пример:

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

Вот мой текущий (не компилируемый) подход:

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
}

Но при вызове

getClassesImplementingProtocol(Animal.Protocol) или

getClassesImplementingProtocol(Animal) или

getClassesImplementingProtocol(Animal.self)

приводит к ошибке Xcode: невозможно преобразовать значение типа (Animal.Protocol). Тип в ожидаемый тип аргумента "Протокол".

Помог ли кто-нибудь справиться с этим?

Ответ 1

Поскольку вы используете среду выполнения Objective-C, чтобы получить интроспекцию типа, вам нужно добавить @objc в свой код следующим образом:

@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")
  }
}

Обратите внимание, что такой тип интроспекции типа может быть очень медленным.