我正在尝试获取已采用某个协议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
}
}
答案 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 {
}