"Can you add member variables through a Category on an existing class?" It was a frequent interview question from long ago. Unfortunately, this question will still be alive in the Swift era.

Thanks to Objective-C runtime and the key-value coding feature, we could add stored values to an object at runtime. However, when used category to extend an existing class, only methods could be added to it. It is not be possible to add a member directly. A workaround is using the property to supply getter and setter, then associate an object to the existing one. After associating, we could access this object from property, it looks like we are operating a member on that object.

Since the Objective-C runtime is still valid in Swift, the same approach could be used. The syntax might be a little bit different. The APIs of getting and setting the associated object in Swift are:

func objc_getAssociatedObject(object: AnyObject!,
                                 key: UnsafePointer<Void>
                             )  -> AnyObject!

func objc_setAssociatedObject(object: AnyObject!,
                                 key: UnsafePointer<Void>,
                               value: AnyObject!,
                              policy: objc_AssociationPolicy)

The parameters of these two APIs are also converted into Swift. Since the safety requirement of Swift, the type is much stricter than what they are in Objective-C. In Swift, we could add an associated object in an extension of some class like this:

// MyClass.swift
class MyClass {
}

// MyClassExtension.swift
private var key: Void?

extension MyClass {
    var title: String? {
        get {
            return objc_getAssociatedObject(self, &key) as? String
        }

        set {
            objc_setAssociatedObject(self,
                &key, newValue,
                .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
}


// Test
func printTitle(input: MyClass) {
    if let title = input.title {
        print("Title: \(title)")
    } else {
        print("not set")
    }
}

let a = MyClass()
printTitle(a)
a.title = "Swifter.tips"
printTitle(a)

// Output:
// not set
// Title: Swifter.tips

We declared the type of key as Void?, which means a pointer to anything. Then & operator is used to get its address and send into the method as UnsafePointer<Void> parameter. It is common to see when using Swift and C together.If you want to know more about these pointer operations and unsafe types, please see UnsafePointer.