尝试获取已采用协议的类列表时出现空白常量

时间:2017-07-13 22:47:13

标签: swift

我正在尝试获取已采用某个协议Migration: Preparation的类的列表,然后将这些类附加到数组中。这是有问题的功能:

struct Migrations {

static func getMigrations() -> [Preparation.Type] {
    var migrationsList = [Preparation.Type]()
    var count = UInt32(0)
    let classList = objc_copyClassList(&count)!


    for i in 0..<Int(count) {
        let classInfo = ClassInfo(classList[i])!
        if let cls = classInfo.classObject as? Migration.Type {
            migrationsList.append(cls)
            print(cls.description)
        }
    }
    return migrationsList
}
}

原则上所有这些都应该有效,但是在调试时我注意到classInfo变量引用了迭代中的每个类,但是当在if let as行中分配和转换时,常量cls是总是空白 - 既不是值/类也不是nil,只是完全空白。

知道我的代码出了什么问题吗?

我也愿意接受任何更好的方法来获取已采用特定协议的所有类的列表......

编辑:我忘了提供ClassInfo

的代码
import Foundation

struct ClassInfo: CustomStringConvertible, Equatable {
    let classObject: AnyClass
    let className: String

    init?(_ classObject: AnyClass?) {
        guard classObject != nil else { return nil }

        self.classObject = classObject!

        let cName = class_getName(classObject)!
        self.className = String(cString: cName)
    }

    var superclassInfo: ClassInfo? {
        let superclassObject: AnyClass? = class_getSuperclass(self.classObject)
        return ClassInfo(superclassObject)
    }

    var description: String {
        return self.className
    }

    static func ==(lhs: ClassInfo, rhs: ClassInfo) -> Bool {
        return lhs.className == rhs.className
    }
}

1 个答案:

答案 0 :(得分:0)

我无法解释为什么cls总是空白的,就像我在评论中说的那样,每次我处理元类型时都会遇到这种情况。至于使代码按预期工作,我发现this q&a并使用Swift 3更新它以获取应该涵盖您的情况的代码。重要的是要强调这只有在你正确地将Swift暴露给Objective-C运行时才会起作用。

将此代码放在任何地方,并从方便的入口点调用print(Migrations.getMigrations())

struct Migrations {

    static func getMigrations() -> [Preparation.Type] {

        return getClassesImplementingProtocol(p: Preparation.self) as! [Preparation.Type]
    }

    static 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
    }

    static func objc_getClassList() -> [AnyClass] {
        let expectedClassCount = ObjectiveC.objc_getClassList(nil, 0)
        let allClasses = UnsafeMutablePointer<AnyClass?>.allocate(capacity: Int(expectedClassCount))
        let autoreleasingAllClasses = AutoreleasingUnsafeMutablePointer<AnyClass?>(allClasses)
        let actualClassCount:Int32 = ObjectiveC.objc_getClassList(autoreleasingAllClasses, expectedClassCount)

        var classes = [AnyClass]()
        for i in 0 ..< actualClassCount {
            if let currentClass: AnyClass = allClasses[Int(i)] {
                classes.append(currentClass)
            }
        }

        allClasses.deallocate(capacity: Int(expectedClassCount))

        return classes
    }
}

class Migration: Preparation {

}

@objc
protocol Preparation {

}