Swift extensions *can* add stored properties

Tikitu de Jager
2 min readOct 31, 2015

--

Ok, the title is a complete lie: Swift extensions can only add computed properties. But you can got something just as good, if you’re willing to use Objective-C associated objects. There’s a lot of boilerplate, though, and if you do it the obvious way you sacrifice type-safety. Can we do better?

Yes we can. Here are a couple of little functions that, by the magic of Swift’s type-inference, let you write type-safe non-Optional computed properties that act just like stored properties, in a class or protocol extension.

import Foundationfunc associatedObject<ValueType: AnyObject>(
base: AnyObject,
key: UnsafePointer<UInt8>,
initialiser: () -> ValueType)
-> ValueType {
if let associated = objc_getAssociatedObject(base, key)
as? ValueType { return associated }
let associated = initialiser()
objc_setAssociatedObject(base, key, associated,
.OBJC_ASSOCIATION_RETAIN)
return associated
}
func associateObject<ValueType: AnyObject>(
base: AnyObject,
key: UnsafePointer<UInt8>,
value: ValueType) {
objc_setAssociatedObject(base, key, value,
.OBJC_ASSOCIATION_RETAIN)
}

That’s all. You use them like so:

class Miller {} // Here's the class we will extendclass Cat { // Every Miller should have a Cat
var name = “Puss”
}
private var catKey: UInt8 = 0 // We still need this boilerplate
extension Miller {
var cat: Cat { // cat is *effectively* a stored property
get {
return associatedObject(self, key: &catKey)
{ return Cat() } // Set the initial value of the var
}
set { associateObject(self, key: &catKey, value: newValue) }
}
}

If you’re following along at home, you can drop the following lines in a playground to confirm that it works as expected.

let grumpy = Miller()
grumpy.cat.name // shows "Puss"
grumpy.cat.name = “Hephaestos”
grumpy.cat.name // shows "Hephaestos"

Easy as that!

Credit where credit is due: at least half of this implementation comes from Eric-Paul Lecluse. He used associated objects in an extension, I extracted the pattern into a reusable class, then together we rendered the class down into the two little functions you see above. The writeup, and any errors it contains, is my own.

--

--

Tikitu de Jager

Musician, programmer, PhD in philosophy of language. Bibliophile, philhellene, pretentious tendencies. Technosceptic. Technoaddict.