Zane Claes
Zane Claes

Reputation: 14954

Listing all `dynamic` variables for a class in Swift2

I'm writing a base class that implements KVO, and I would like to infer the names of the dynamic attributes of the class. For example:

class BaseClass {
  func beginObserving() {
    // What are the dynamic attributes to observe?
    // In the case of "SubClass" below, it should be ["name"]
    let attributes = ???
    for attribute in attributes {
      self.addObserver(self, forKeyPath: attribute, options: [.New, .Old], context: &KVOContext)
    }
  }
}

class SubClass : BaseClass {
  dynamic var name: String!
}

List of class's properties in swift explains how to do this with Mirror (reflection), but it does not appear to work for dynamic vars (i.e., if I removed the dynamic keyword the linked code would work for this case).

Upvotes: 1

Views: 67

Answers (1)

Rob
Rob

Reputation: 437472

You can use the standard <objc/runtime.h> functions:

class MyObject {
    dynamic var identifier = 0

    func dynamicProperties() -> [String] {
        var dynamicProperties = [String]()

        var propertyCount = UInt32(0)
        let properties = class_copyPropertyList(object_getClass(self), &propertyCount)
        for var i = 0; i < Int(propertyCount); i++ {
            let property = properties[i]
            let propertyName = property_getName(property)
            dynamicProperties.append(String(CString: propertyName, encoding: NSUTF8StringEncoding)!)
        }
        free(properties)

        return dynamicProperties
    }
}

--

If you want subclasses to show not only their properties, but also those of its superclass, you can do the following:

class BaseClass {
    dynamic var identifier = 0

    func dynamicProperties() -> [String] {
        var dynamicProperties = [String]()

        var propertyCount = UInt32(0)
        let properties = class_copyPropertyList(object_getClass(self), &propertyCount)
        for var i = 0; i < Int(propertyCount); i++ {
            let property = properties[i]
            let propertyName = property_getName(property)
            dynamicProperties.append(String(CString: propertyName, encoding: NSUTF8StringEncoding)!)
        }
        free(properties)

        return dynamicProperties
    }
}

class SubClass : BaseClass {
    dynamic var name: String!

    override func dynamicProperties() -> [String] {
        var dynamicProperties = super.dynamicProperties()

        var propertyCount = UInt32(0)
        let properties = class_copyPropertyList(object_getClass(self), &propertyCount)
        for var i = 0; i < Int(propertyCount); i++ {
            let property = properties[i]
            let propertyName = property_getName(property)
            dynamicProperties.append(String(CString: propertyName, encoding: NSUTF8StringEncoding)!)
        }
        free(properties)

        return dynamicProperties
    }

}

Upvotes: 1

Related Questions