List of class's properties in swift List of class's properties in swift swift swift

List of class's properties in swift


Using Mirror

Here's a pure Swift solution with some limitations:

protocol PropertyNames {    func propertyNames() -> [String]}extension PropertyNames{    func propertyNames() -> [String] {        return Mirror(reflecting: self).children.flatMap { $0.label }    }}class Person : PropertyNames {    var name = "Sansa Stark"    var awesome = true}Person().propertyNames() // ["name", "awesome"]

Limitations:

  • Returns an empty array for Objective-C objects
  • Will not return computed properties, i.e.:

    var favoriteFood: String { return "Lemon Cake" }
  • If self is an instance of a class (vs., say, a struct), this doesn't report its superclass's properties, i.e.:

    class Person : PropertyNames {    var name = "Bruce Wayne"}class Superhero : Person {    var hasSuperpowers = true}Superhero().propertyNames() // ["hasSuperpowers"] — no "name"

    You could work around this using superclassMirror() depending on your desired behavior.

Using class_copyPropertyList

If you're using Objective-C objects you can use this approach:

var count = UInt32()let classToInspect = NSURL.selflet properties : UnsafeMutablePointer <objc_property_t> = class_copyPropertyList(classToInspect, &count)var propertyNames = [String]()let intCount = Int(count)for var i = 0; i < intCount; i++ {    let property : objc_property_t = properties[i]    guard let propertyName = NSString(UTF8String: property_getName(property)) as? String else {        debugPrint("Couldn't unwrap property name for \(property)")        break    }    propertyNames.append(propertyName)}free(properties)print(propertyNames)

The output to the console if classToInspect is NSURL:

["pathComponents", "lastPathComponent", "pathExtension", "URLByDeletingLastPathComponent", "URLByDeletingPathExtension", "URLByStandardizingPath", "URLByResolvingSymlinksInPath", "dataRepresentation", "absoluteString", "relativeString", "baseURL", "absoluteURL", "scheme", "resourceSpecifier", "host", "port", "user", "password", "path", "fragment", "parameterString", "query", "relativePath", "hasDirectoryPath", "fileSystemRepresentation", "fileURL", "standardizedURL", "filePathURL"]

This won't work in a playground. Just replace NSURL with EachDayCell (or reuse the same logic as an extension) and it should work.


Here is another version.I think this is much simple and pure.

Swift 2.0

protocol Reflectable {  func properties()->[String]}extension Reflectable{    func properties()->[String]{        var s = [String]()        for c in Mirror(reflecting: self).children        {            if let name = c.label{                s.append(name)            }        }        return s    }}class Test:Reflectable{    var name99:String = ""    var name3:String = ""    var name2:String = ""}Test().properties()

Swift 1.2

class Reflect:NSObject {    func properties()->[String]    {        let m = reflect(self)        var s = [String]()        for i in 0..<m.count        {            let (name,_)  = m[i]            if name == "super"{continue}            s.append(name)        }        return s    }}class Test:Reflect{    var name99:String = ""    var name3:String = ""    var name2:String = ""}Test().properties()


I converted bolivia's code to Swift 4. This function takes in an NSObject and returns a dictionary of the object's keys and the type of that key.

Note that the types are kind of ugly. For primitive properties the engine returns a one letter identifier (like B for bool, i for int, etc) but for Obj-C types it returns things like @"NSString". Seeing as this is really just a debugging function for me I didn't mind. If you don't want to mess with the dictionary you can just uncomment the print line and get it dumped to the console. String(cString:cAttr) also contains a lot of useful info including if the property is mutable, it's reference style, and much more. For more info on this here's Apple's documentation.

func getKeysAndTypes(forObject:Any?) -> Dictionary<String,String> {        var answer:Dictionary<String,String> = [:]        var counts = UInt32()        let properties = class_copyPropertyList(object_getClass(forObject), &counts)        for i in 0..<counts {            let property = properties?.advanced(by: Int(i)).pointee            let cName = property_getName(property!)            let name = String(cString: cName)                        let cAttr = property_getAttributes(property!)!            let attr = String(cString:cAttr).components(separatedBy: ",")[0].replacingOccurrences(of: "T", with: "")            answer[name] = attr            //print("ID: \(property.unsafelyUnwrapped.debugDescription): Name \(name), Attr: \(attr)")        }        return answer    }