How Blockchain is disrupting Advertising Industry

Blockchain is gradually being adopted by more and more industries like Healthcare, supply chain and logistics, Education, Food, Entertainment, etc. This is due to the Blockchain features and the…

Smartphone

独家优惠奖金 100% 高达 1 BTC + 180 免费旋转




Indirection is the solution

The Swift standard library does a great job at providing us with collection types that perform very efficiently with respects to their memory footprint. This performance is due to a mechanism know as copy-on-write, which allows types such as Array to delay copying operations until the very moment where they become required to guarantee correctness of the program. Consider the following code:

So what happened? Basically, Array is a smart type so it waits until its content is really about to be mutated to perform the copy. This way, all unnecessary — and potentially costly — copy operations are never carried out.

Unfortunately, this behavior does not come for free with every struct type, if you require it for one of your custom types, you will need to implement it from scratch.

To do so, we will rely on a couple of wrapper types, that will nicely encapsulate the copy-and write logic.

We start with a helper type that will allow us to add a layer of indirection to any value:

The class CopyOnWriteRef is basically a pointer to a value. Notice that it is declare as final and does not inherit from NSObject – thus it is not marked @objc. This enables the swift compiler to perform a whole range of optimizations when our code will interact with this class.

Then, we define the wrapper that actually implements the copy-on-write logic:

Notice that CopyOnWriteBox is defined as a struct that stores a reference to a class (CopyOnWriteRef). This way, when the struct will get copied, the compiler will only perform a shallow copy of the field ref, meaning that the new struct will refer to the same memory address as the old one.

The logic behind the copy-on-write is actually rather easy to implement, thanks to the isKnownUniquelyReferenced function that does a lot of heavy lifting. This function takes as argument a reference to an object, and indicates whether there exists only a single strong reference to this object.

From this, the rest is pretty straightforward: we define a computed property to encapsulate ref, and in the setter we check if multiple strong references to ref exist, which means that several structs share a reference to the same value, in which case we perform the copy.

To check that everything is working fine, we first define a custom type Point, and we wrap it to provide copy-on-write:

And then we use the same test case than before:

And, indeed, we have achieved to implement a copy-on-write mechanism for a custom Swift type 😁

🚨🚨🚨 Be careful! This implementation of copy-on-write is only going to work for value types (meaning struct and enum).

Should you try to apply it to wrap a reference type, say NSMutableAttributedString for instance, it would not be working, because the affectation performed in CopyOnWriteRef.init would not result in a deep-copy, as it does with value types, but only in a shallow-copy of the reference to the object.

Keep also in mind that such an optimization comes at the cost of additional code, so it should only be used to solve actual performance issues. I would not recommend to apply it preventively.

Add a comment

Related posts:

Misfired Story

This is a true story of what happened when I decided to do a kindness for an early reader. Rather than foist a digital manuscript on a person who only reads paper, I printed out the pages after…

I Finally Met With A Psychologist

The wait finally ended. After two months of being on a waiting list, I was finally able to meet with a psychologist. I want to start by saying that the long line was worth it. I’ve never had therapy…

Sederstrom

Sederstrom and Sederstrom, the Swedish precursor on which the more popular American show was based. Sederstrom was the smart-alecky one, always after the ladies, while his long-suffering brother went…