Swift Concurrency Deep Dive [3] — Structured concurrency

enebin
4 min readNov 2, 2022

--

Photo by Bozhin Karaivanov on Unsplash

This post is written for a deeper understanding of Swift concurrency, that is, async/await.

I’ve collected information from reliable sources like Apple Developer’s Document, Swift-evolution repository or Swift Language Guide as much as possible, but may contain incorrect information. In that case, please let me know in the comments.

I highly recommend you to read my previous series.

Structured programming paradigm

Concept of structured & unstructured

📒 from Wikipedia
Structured programming is a programming paradigm aimed at improving the clarity, quality, and development time of a computer program by making extensive use of the structured control flow constructs of selection (if/then/else) and repetition (while and for), block structures, and subroutines.

To put it very simply, structured programming means that the codes are executed in the order it’s written, so to speak, procedurally.

Here is example Swift code that implements structured programming.

You can easily notice that the trailing code is executed only when all preceding codes are completed.

When it’s expressed using completion handler pattern, it can be like:

In this case, unlike the first example, completion of the trailing code affects the preceding code. It can be said that the code is designed unstructured.

Swift’s old concurrency codes are unstructured

Unstructured flow graph from Explore structured concurrency in Swift — WWDC21

Before Swift concurrency was introduced, concurrency programming in Swift had to be done mostly in an unstructured way as the example we saw.

Using DispatchQueue’s async and Combine's Publisher, we’ve had to use a callback function to get the results. Unfortunately, using them, our codes couldn’t help but being written in unstructured way.

Unstructured programming, where the trailing code can affect the preceding code, reverses natural reading order, thus ruining readability and creating error-prone structure.

Due to these reasons, the need for structured code in asynchronous programming in Swift had emerged and as a result, Swift concurrency was proposed.

Structured concurrency in Swift

Structured programming can be said as the core concept of Swift concurrency. You can get a glimpse of makers’ intention from proposal document written in Swift-evolution repository and WWDC session, Explore structured concurrency in Swift — WWDC21.

Now, let’s take a look at differences between structured and unstructured programming in Swift through URLSession.

First example is the way using completionHandler, which has been used commonly so far.

It has following features:

  • It’s a function receiving callback when the dataTask is completed, using a closure, completionHandler.
  • In here, you must directly call completionHandler to deliver the processed image outside.
  • In addition to pass the data, Result type was used to throw error outside.

Second example is the code using async/await, changed from completionHandler.

It has following features:

  • Since data loading is suspended with await, all code will stop at that point until the operation is completed.
  • When the operation’s done, the result data will be saved in the variable data.
  • Now code will resume from the suspension point and then creates an image with the data. After that, task returns image.

As you saw, code will be executed in the order in which it’s written, which can be said structured.

Comparison

From Explore structured concurrency in Swift — WWDC21

In the first example, using completionHandler, it has a problem that result can not be passed if someone forgot to call completionHandler. It’s one of the common problems code using completion handler pattern has.

However, in the second example, using async/await, result is passed without using completionHandler, so potential errors it has disappear.

Also, no need for using Result type, you can throw an error right away using the keyword try. Using throw is also allowed.

Thanks to all of these features, code becomes more shorter and legible, in addition to get some improvement of performance.

Task?

By the way, we’ve used the keyword Task unconsciously.

In a nutshell, Task is a unit of async job in Swift concurrency and its initializer helps making unstructured concurrency in Swift concurrency’s context.

Okay, it seems right time to dig deeper into the Task.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

enebin
enebin

Written by enebin

Making your dreams a reality |  Mainly Interested in iOS | https://github.com/enebin

No responses yet

Write a response