簡體   English   中英

如何在 Swift 中列出所有符合協議的類?

[英]How to list all classes conforming to protocol in 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).Type 的值轉換為預期的參數類型“Protocol”。

有沒有人設法讓這個工作?

由於您正在使用 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")
  }
}

請注意,這種類型自省可能非常慢。

在速度方面,您可以在一個 for 中完成,並避免像這樣遍歷所有類:

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

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM