Swift 获取类的所有子类和属性列表

闽阳州
2023-12-01
import Foundation


/// 如果需要用对应的类型,字典定义Dictionary<String, Any>,对应value为Int8.self、Int16.self,下面用到的方法都需要更改为Dictionary<String, Any>
let valueTypesMap: Dictionary<String, String> = [
    "c" : "Int8",
    "s" : "Int16",
    "i" : "Int32",
    "q" : "Int", //also: Int64, NSInteger, only true on 64 bit platforms
    "S" : "UInt16",
    "I" : "UInt32",
    "Q" : "UInt", //also UInt64, only true on 64 bit platforms
    "B" : "Bool",
    "d" : "Double",
    "f" : "Float",
    "{" : "Decimal"
]

extension NSObject {
    
    /// 获取继承自该类的所有子类
    ///
    /// - Returns: 子类名称数组
    class func subclasses() -> [NSString] {
        var count: UInt32 = 0, result: [NSString] = []
        let allClasses = objc_copyClassList(&count)!
        
        for n in 0 ..< count {
            let someClass: AnyClass = allClasses[Int(n)]
            guard let someSuperClass = class_getSuperclass(someClass), String(describing: someSuperClass) == String(describing: self) else { continue }
            //返回的类会带module名,如果把module名截取了,就无法转换成对应的类了
            let className: NSString = NSStringFromClass(someClass) as NSString
            
            result.append(className)
        }
        return result
    }
    
   /// 获取属性名和类型列表
   ///
   /// - Returns: 属性名和类型的字典
   class func getProperties() -> Dictionary<String, String>? {
        var count = UInt32()
        guard let properties = class_copyPropertyList(self, &count) else { return nil }
        var types: Dictionary<String, String> = [:]
        for i in 0..<Int(count) {
            let property: objc_property_t = properties[i]
            /// 获取属性名
            guard let name = getNameOf(property: property)
                else { continue }
            /// 获取属性类型
            let type = getTypeOf(property: property)
            types[name] = type
        }
        free(properties)
        return types
    }
    
   /// 获取属性名
   ///
   /// - Parameter property: 属性对象
   /// - Returns: 属性名
   private class func getNameOf(property: objc_property_t) -> String? {
        guard
            let name: NSString = NSString(utf8String: property_getName(property))
            else { return nil }
        return name as String
    }
    
   /// attributes对应的类型
   ///
   /// - Parameter attributes: attributes
   /// - Returns: 类型名
   private class func valueType(withAttributes attributes: String) -> String? {
        let tmp = attributes as NSString
        let letter = tmp.substring(with: NSMakeRange(1, 1))
        guard let type = valueTypesMap[letter] else { return nil }
        return type
    }
    
   /// 获取属性类型
   ///
   /// - Parameter property: 属性对象
   /// - Returns: 属性类型
   private class func getTypeOf(property: objc_property_t) -> String? {
        guard let attributesAsNSString: NSString = NSString(utf8String: property_getAttributes(property)!) else { return nil }
        let attributes = attributesAsNSString as String
        let slices = attributes.components(separatedBy: "\"")
        guard slices.count > 1 else { return valueType(withAttributes: attributes) }
        let objectClassName = slices[1]
        return objectClassName
    }
}

@objcMembers//必须有这一句,否则无法获取该类的所有属性列表
class Person: NSObject {
    var id : Int = 0
    var name: String = ""
    var female: Bool = false
    
}

P.S:只能获取公有属性

 类似资料: