Bad practice: using an unsafe continuation


You’re more of a video kind of person? I’ve got you covered! Here’s a video with the same content than this article 🍿


Can you guess what’s the problem with this code?

Here we’re making a legacy asynchronous function, that relies on a completionHandler, compatible with the modern async / await syntax.

And to achieve this, we’re using the function withUnsafeContinuation.

But you might already know that there’s another function that seemingly performs the same job: a function called withCheckedContinuation

So what’s the difference between these two functions?

The difference lies around the continuation.

The documentation states that the continuation is an opaque representation of the state of our program and that it must be called exactly once.

And that’s where the difference lies: withCheckedContinuation will add runtime checks to detect any improper use of the continuation and warn you if it were to happen.

But on the other hand, withUnsafeContinuation will perform none of these checks.

So let’s see what happens if we make a mistake in how we use the continuation!

If we forget to call the continuation, then our program will be awaiting for ever. But when using a checked continuation, we get a warning in the console 👍

And if we call the continuation more than once, the unsafe version will result in undefined behavior whereas the checked version will crash explicitly.

So if you go with the unsafe approach and misuse the continuation, it will be much harder to notice it, especially in production 😔

But then why do we even have the option of using withUnsafeContinuation?

It’s because these additional checks come with a small cost.

And in some performance heavy situations, it can make sense to disable them.

However, in most cases this shouldn’t be an issue and you’ll be much better using withCheckedContinuation because of the extra safety it provides.

That’s all for this article: I hope it will help you avoid sneaky production bugs in the future!

Here’s the code if you want to experiment with it:

await withUnsafeContinuation { continuation in
    legacyAsyncFunction { result in
        continuation.resume(returning: result)
    }
}

await withCheckedContinuation { continuation in
    legacyAsyncFunction { result in
        continuation.resume(returning: result)
    }
}
Previous
Previous

Here are 3 cool new features of Swift 5.9 🤩

Next
Next

Here’s what you need to know about TipKit! 💡