Stored properties and extensions: a pure Swift approach
One of the most common question regarding swift extensions is about stored properties. How many times have you wished a stored property within your last-super-cool extension in order to parametizer some behaviours?
As you may know Swift does not allow stored properties into extensions. That’s by design: “Extensions may not contain stored properties.”
The most common newbie error is try to overcome the above by implementing something as follow:
Even the above code will compile with no errors, you will realize sooner that it is completely wrong; in fact, the cycling reference to the computed property will loop your code until the heap will be saturated by almost identical calls.
The second common approach is googling around. You will stumble across some nifty workarounds in order to add something that resemble the stored properties concept to use inside extensions (see References).
One of the most (ab)used workaround consist of relying into Objective-C runtime, by adopting a solution based on objc_getAssociatedObject and objc_setAssociatedObject functions.
Even if there is nothing wrong in these solutions it would be much more elegant a pure swift approach. That’s the reason about this post: attempting to create a pure swift extension with support for stored properties.
The proposed solution is very simple. It is based on the assumption that extensions don’t accept stored properties but computed ones. By elaborating and digging around the by-value Structs concept, we eventually hack the extensions design adding, in fact, the concept of stored properties. Completely in Swift.
A proof-of-concept is a lot more useful than thousands of words. So here we go:
The Holder struct will contain the private value that our computed property will expose to the world, giving the illusion of a stored property behaviour instead.
29/03 — Update
As outlined by Paolo, even if the above approach is working, it should be reviewed at least in two parts in order to solve the following:
- Private scoping for the Holder struct (actually, everyone can access the service static Structs changing the value without further controls).
- Multiple instances of the extended class. The proposed approach suffer of a very nasty problem: if you create multiple instances of the extended class, every instance will share the same static value from the Holder struct. The problem is related to the nature of the static keyword: Every instance of the extended class will share the same static value from the Holder struct. We can use a little bit of imagination in order to be creative and solve the issue.
The following should do the trick:
Here, we exploited some sort of hash table in order to hold all the possible different values belonging to different class instances. Please note that self.debugDescription is a really “raw” approach and we should elaborate a more concise and smart way to distinguish between different references of different classes. But, in any case, it seems working as a poc.
30/03 — Update
I couldn’t imagine that there was a so huge interest on this topic! Many thanks to all. There is still a margin of improvement in this approach and after a very kindly discussion with my friend Davide, I decided to give a follow up to the article in order to include some of his suggestions as well as to improve the hash table. Since we use a static var to emulate an hash table, there is no reason to still rely on the Struct approach. Agree. Definitely, this will save a lot of lines of code. Also, I would like to improve the hash table key mechanism by using memory address like pointers. The new version of the approach is as follow:
Much, much better! …there is still a minor issue regarding “memory leaking”…but this is another story…
Happy swifty coding!
The Swift Programming Language (Swift 4.1): Extensions
The definitive guide to Swift, Apple's programming language for building iOS, macOS, watchOS, and tvOS apps.
Stored Properties In Swift Extensions - Marco Santa Dev
One of the main limitations of Swift Extensions is the impossibility to use stored properties. Let's see a workaround…
Swift extensions *can* add stored properties
Ok, the title is a complete lie: Swift extensions can only add computed properties. But you can got something just as…
Four Clever Uses of Swift Extensions
If you're watching this, then I assume you're familiar with Swift extensions. A Swift extension allows you to add…
Stored Properties in Swift Extensions - DZone Mobile
You can now use stored properties in Swift Extensions to add new functionality to an existing class, structure, or…
Swift Extensions Part 1 - Computed Properties and Initializers
So, there has been a reason for my most recent choice of topics to discuss. This isn't some grand culmination post, but…