Paid Article Unlocked 🔓 Forbidden Swift
Thanks for reading Jacob’s Tech Tavern! To say thanks for your support so far, I’m giving you one of my favourite paywalled articles for free. If you enjoyed it, take advantage of my flash sale, ending Friday. Without further ado, here’s: The Swift Apple doesn’t want you to know. I’ve been writing Swift daily for nearly 10 years. I’m impostor syndrome-proof. I’ve seen it all. But every so often… I don’t know. Maybe I make a typo in Xcode that unearths forgotten creatures from the Mariana Trench of autocomplete. Perhaps I’m buying pet chimps on the darkweb and accidentally stumble upon a blog post containing arcane syntax. Today, we’re going to unearth some of the Swift which Apple keeps in the cupboard under the stairs. We’ll ascertain whether these keywords and functions have any real-world use cases, so we can take them out for a bit of sun.
unowned(unsafe)We all know about strong, weak, and unowned… but there’s a 4th type of reference that Apple is afraid to put in its libraries (mostly), because of how dangerous it can be. Unowned references, while slightly more performant than weak, actually do involve some overhead. The Swift runtime checks whether the reference is still valid, and crashes your code if not. (I don’t like them much). unowned(unsafe) skips those pesky runtime memory safety checks to save a few extra clock cycles. When you access a deallocated unowned(unsafe) reference, we get undefined behaviour. This means sometimes it might simply crash… Or, just for fun, perhaps you’ll be able to access the memory inside the dead reference: This might seem innocuous enough to you, but remember that most system-level exploits (think dismemberment) are predicated on messing around with corrupted memory. withoutActuallyEscapingThis is actually the reason I started writing this article. I saw this code block in a very interesting blog post by Wade Tregaskis about making a synchronous version of Task. What on earth is withoutActuallyEscaping?! You can’t understand this without a refresher on the two kinds of closure.
(@escaping () → Void) and (() → Void) are two separate types, and incompatible. You can’t just put a non-escaping closure somewhere designed for an escaping one—for example, in a Task initialiser. That’s where withoutActuallyEscaping comes in. It’s implemented via a special case in the Swift type checker, temporarily loosening type system rules inside the closure. This allows a non-escaping closure to temporarily be used as if it’s @escaping. It can run as if it’s escaping, without actually escaping the synchronous scope. Apple uses this in the Standard Library, for example to implement MainActor.assumeIsolated: dlopen()This is another function based on a blog post—one actually inspired by me, when I questioned the genius of Scott Yelvington. He proved that you can actually lazy-load dynamic libraries to create a plugin architecture on iOS apps. I was very happy to be proved wrong. Long story short, you can’t remote-update specific modules, but lazy loading is a-ok as long as the dynamic modules are bundled with your app. To do this, you clear out the framework from the compiler’s Link Binary With Libraries phase, create an interface framework to bridge to your dynamic module, then load the framework in at runtime via its path. dlopen is the Darwin interface to the dynamic loader, dyld. This loads the binary into (a randomised address in) memory, recursively loads its sub-dependencies, then returns an UnsafeMutableRawPointer to the memory address of the module. Seriously, read Scott’s article, it’s a banger. malloc, free, and withUnsafeTemporaryAlloationAs this Swift evolution proposal explains, in order to provide the high level memory-safe interface that we work with every day, Swift requires some amount of low-level unsafety. For example, Data relies on the UnsafeRawPointer and Array uses UnsafeMutableRawBufferPointer. This is a side to Swift we never see. While us app developers are gallivanting around at conferences arguing about SwiftUI frame drops, library engineers are in the C and Builtin mines, painstakingly arranging the bits that give us our performance. Interestingly, we can call C standard library functions directly because Swift code implicitly imports Darwin when running on Apple platforms. withUnsafeTemporaryAllocation is a global function that was pitched to enable an optimisation that is very popular in C and C++: directly allocating temporary buffers of memory on the heap. I originally clocked this unsafe menagerie thanks to this Tweet (that also gave me lots of impostor syndrome, I’m still a little unsure if Marcin was joking or not). _modifyGetters and setters allow us to create fun side effects when reading and writing the value of mutable computed properties. When you use setters to mutate an existing value, they are actually 3 separate operations:
This works fine for most cases, but can hide serious performance problems, especially when using types like strings, dictionaries, or any heap-buffer-backed type that relies on the copy-on-write optimisation. During the set operation, a copy is made, then written to—triggering a full deep copy for the entire heap buffer. This is an O(n) operation, which means any loop involving a computed string setter, or dictionary subscript, might quietly run in quadratic complexity or worse. The _modify accessor avoids this pitfall by enabling in-place mutation without creating any copies. Instead of copying the value (and potentially creating an additional reference, triggering copy-on-write for the backing heap object), it yields a reference to this underlying storage. Yield is a contextual keyword that allows the accessor to borrow the reference, operating on the object’s heap memory without incrementing its reference count. This can be a very useful tool in your toolkit, particularly if you are a library author trying to build the most efficient possible collections. But you should not just use it every time you need property accessors—it is only more efficient in specific scenarios. This information was mostly borrowed from the legendary Ben Cohen’s proposal for the _modify accessor, which is up for promotion from lowly underscored property to a legit keyword very soon. autoreleasepoolThis is actually the most useful tool of the bunch. While on first glance this looks like a crufty holdover from pre-ARC days, alongside retain() and release(), autorelease pool is useful today to fix out-of-memory crashes and performance issues. Seriously, I used it today*.
autoreleasepool wraps a closure. This quietly tracks all the heap objects created within its scope, and sends a RELEASE message to each of them when the block exits. This allows temporary objects to live just as long as needed, then deallocate as soon as they aren’t required. In practice, this means a temporary variable in a long loop won’t need wait until leaving function scope before deallocating. This can dramatically smooth out peak application memory during long or expensive processing. Let’s try it out: we will profile this code in the Xcode debugger. With an autorelease pool block, each chunk of data and UIImage are released upon leaving the scope of the pool. Therefore the loop iterations don’t add up, and peak memory use stays nice and level. If you try removing the autoreleasepool block, we quickly see why it’s useful. Consider using autorelease pool whenever you are looping through many heavy reference-counted objects. I have personally used this for:
Last OrdersPerhaps you were enthralled by this list of arcane language features. Or, perhaps you’re a low-level library author and think this summary was a bit quaint. You work on a side to this language that most mortals never conceive of. For the rest of us; let’s pour one out for those working in the SIL, C++, and standard library mines, helping to truly make our language Swift. These forbidden Swift artefacts all have something in common: you shouldn’t use them very often. But, occasionally, you might have a sharp performance problem, perhaps a very hot function or a huge loop that generates a memory spike. Maybe your code is just a bit too slow to launch. In these rare instances, pulling one of these tools out of the ether will demonstrate your mettle as an engineer.
|

![The Case Against [unowned self]](https://substackcdn.com/image/fetch/$s_!bPd6!,w_1300,h_650,c_fill,f_auto,q_auto:good,fl_progressive:steep,g_auto/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86735ea4-3f47-4ef5-9a26-a1b164444fcf_1400x1050.jpeg)












