Here are some thoughts I’d like to share when it comes to Arrays in Swift.
If you’re looking for more information, check out this very good post about memory management in Rust and Swift.
Apple Docs are quite explicit :
For arrays [memory] storage can be a contiguous block of memory or an instance of NSArray.
Arrays are stored in a contiguous block of memory, of course they are.
This is nothing new, but if that’s so, what happens when you append an element to an Array?
Relocation occurs when the size of an object exceeds the memory available in its block.
Seems so obvious while reading, isn’t it?
The object is moved to a larger block and the address changes.
This is also possible causes of Memory Leaks, but I leave this story for an other day.
Suppose you are in a very busy and threaded environment… An array changes address… What will happen? Will all the threads be able to access the values properly?
Bad Access and Heap Corruption
Sometimes things might go bad.
You will get a shitty EXC_BAD_ACCESS with little-to-no explanation.
If you’re lucky, you will notice that the address of the incriminated array in the debugger differs from the one that caused the error – of course, it has been moved!
Put together relocation and leaks, and in the worst case you’ll get an Heap Corruption.
How to avoid Array Relocation
My advice is to take this seriously from the start.
Do not fear to write a few more lines of code and reserve capacity for array elements, so they won’t be relocated.
This can be done easily by calling the method reserveCapacity(:_) :
var fruits = ["banana", "strawberry"] fruit.reserveCapacity(5) fruit.append("apple") fruit.append("google") // Not a fruit, but for par condicio fruit.append("an other banana")
You can also reserve memory you don’t use, which might be an easy option if you don’t know the exact number of elements.
Extension of the day
I love extensions.
If you are particularly lazy – like I am, that’s why a love extension – check this simple extension, that will allow you to init an empty array and reserve capacity in one line.
var fruits = [String](withReservedCapacity: 5)