A gentle introduction to async/await in Swift

Ian Walton/Getty Images

Swift was announced at WWDC 2014, and at the end of 2015, it was made open-source under the Apache License 2.0 (with some exceptions). If you have been following along since the beginning, the language had so many changes, especially on the surface (syntax), that after some period of time they almost became a developer joke, like whether the changes were to rename methodX to aMethodX in the next release (credits to good ol’ Xcode who would do the most of the migration automatically).

This is, of course, also due to the nature of the open-source software. The exception with Swift is, in my opinion, that it now became a software language that’s (well, to a certain degree) community-driven, but also has the resources to continue its evolution, having a tech titan behind. It’s hard to argue with the assessment that this is an amazing thing for the community and the software itself.

One of the things that I like about the open-source software development is the transparency. You are able opt-in all the events in the life of a feature even from the very beginning. Which means, if you really want to, you can even be a part of the change yourself. If not, you can just keep monitoring and get excited about it until it’s released, and who knows, maybe you will already be a master of the feature by the time it’s released!

If you are here before async/await is released or announced very publicly (I guess it means to get promoted during WWDC, etc.), then you are probably in the second group I mentioned above. After raising awareness regarding what a great thing open-source software is, we can finally talk about it.

Why?

There’s this proposal that’s made for the feature and I’ll try to summarize it below, leaving some comments. It makes sense to start with the “why” which is explained very well in the “Motivation” section of the proposal, roughly as follows:

Problem 1: Pyramid of doom

The pyramid of doom is a common problem that arises when a program uses many levels of nested indentation to control access to a function.

Wikipedia

Closures. As soon as we learned how to use them, we started building these pyramids ourselves, embedding one closure in another. Apparently, over time it became so disturbing for everyone that it is mentioned as the first reason for this change.

Problem 2: Error handling

Callbacks make error handling difficult and very verbose. (…) The addition of Result to the standard library improved on error handling for Swift APIs. Asynchronous APIs were one of the main motivators for Result. It’s easier to handle errors when using Result, but the closure-nesting problem remains.

Problem 3: Conditional execution is hard and error-prone

If you really wonder what that really means, see here, but basically, the problem is:

This pattern inverts the natural top-down organization of the function: the code that will execute in the second half of the function must appear before the part that executes in the first half.

Even though I agree with the problem, the example that was given in the link doesn’t seem like the perfect fit, I mean, why don’t you just create a new method rather than creating a closure and assign it to a constant? But anyway, this doesn’t change the fact that this problem does exist when you can’t just export the code into a method.

Problem 4: Many mistakes are easy to make

It’s quite easy to bail-out of the asynchronous operation early by simply returning without calling the correct completion-handler block.

It simply means that you have something to do as soon as your closure is about to exit, but if you have lots of conditions inside of your closure and in some of them you exit the closure earlier, it’s easy to forget your last step code before exiting the closure. This happened to me many times, I’m sure it happened to you as well.

Problem 5: Because completion handlers are awkward, too many APIs are defined synchronously

Seriously? That’s just… Sad.

I think everything above is somewhat reasonable, but the ones that I agree with the most are #1 and #4.

Solution in a nutshell

Asynchronous functions—often known as async/await—allow asynchronous code to be written as if it were straight-line, synchronous code.

So, for example, this:

func printDelayedVar() {
    self.getMyDelayedVar { (delayedVar) in
        print(delayedVar)
    }
}
​
func getMyDelayedVar(completion: (Int) -> Void) {
    DispatchQueue.main.async {
        sleep(3)
        completion(5)
    }
}

Becomes this:

@asnycHandler func printDelayedVar() {
    let delayedVar = await self.getMyDelayedVar()
    print(delayedVar)
}
​
func getMyDelayedVar() async -> Int {
    // Code to be revealed in the rest of the article
}

No reason to worry because of your pyramids getting lost. We still neste things within one another inside of the async methods, but at least we call our async method like a synchronous method in printDelayedVar. I guess the pyramids are just getting… Smaller?

Before moving further, I want to make a disclaimer that the part that I’m covering in this post is simply the tip of the iceberg. In the announcement post of the approval of this proposal, the review manager says:

This is an important first step on our concurrency journey. To help navigate how this proposal relates to expected future proposals, this diagram should be of help:

Swift Concurrency Dependencies
Swift Concurrency Dependencies

As you can see, concurrency in Swift is in fact just getting warmed up. If you want to learn more about this feature, see the References section at the end of the page.

async/await hands on

Before experimenting with this syntax, there are a couple of things we need to do:

1. Download and install the latest* development snapshot from swift.org.

Go to https://swift.org/download/#snapshots and from the section ‘Trunk Development (main)’, download and install the one that’s for Xcode.

* Some things might have changed until the time you read this post, so try this alternative snapshot if things work out differently for you after you install.

2. Configure Xcode to use the respective toolchain

Open Xcode and from the Xcode menu, select Toolchains -> Swift Development Snapshot YYYY-mm-dd. You can do the same through Preferences -> Components -> Toolchains.

3. Add flags to enable experimental feature

From your Project’s build settings, find Swift Compiler - Custom Flags section and add the following flags to Other Swift Flags section: -Xfrontend -enable-experimental-concurrency.

4. Import experimental concurrency module

Add import _Concurrency to the header of the file that you are going to use for experimenting the feature. Note the underscore (_) in the beginning of the name of the module which indicates that it’s yet under development.

Done! You can now use async/await in your code. Xcode won’t highlight them yet but it will nicely compile and won’t block your way.

How to use async/await

By the time this feature is released, it’s quite likely that Apple will have converted some (hopefully many) asynchronous methods to async, but right now, we need to build our own async method. To do that, we will use a helper that comes with the _Concurrency module, that is, withUnsafeContinuation. We’ll come to that in a second.

The “sad” code (what we already do)

Assuming what you see below is the code you want to rewrite using async/await because you are unhappy with it (because of the problems we mentioned above):

class SendSelectedPhotoWithEmailViewController: UIViewController {
    func startFlow() {
        // Get access to user's photo library, when the access is granted, display photo picker.
        // When the user picks a photo, first upload it to the server, then send the uploaded file URL
        // via email. Finally, show the user the result of the process.
        PhotosAPI.grantPhotosAccess { didGrantAccess in
            if didGrantAccess {
                PhotosAPI.selectPhoto { selectedPhoto in
                    NetworkAPI.upload(image: selectedPhoto) { uploadedFileUrl in
                        NetworkAPI.sendUrlWithEmail(urlString: uploadedFileUrl) { [weak self] didSend in
                            self?.displayResultAlert(didSendEmail: didSend)
                        }
                    }
                }
            }
        }
    }
}

We will not convert every method above since the logic is almost the same. We will just convert one for demonstration and refactor the other lines as if the corresponding methods were also converted.

Let’s pick NetworkAPI.upload(image:completion:) method. If we were mocking the API and faking the network delay using sleep, the method would be something like this:

static func upload(image: UIImage, completion: @escaping (String) -> Void) {
    DispatchQueue.main.async {
        sleep(1) // Fake wait
        completion("fake URL")
    }
}
  • Problem 1: Our method deals with asynchronous code so it cannot return anything. That’s why it takes a closure where it passes the result.
  • Problem 2: When we use the trailing closure syntax in the place we call this method and embed such methods within each other, things get out of control.

The “happy” code (async/await)

Here, let’s create a method step by step, keeping the problem duo above in mind, and hopefully fix them.

We start with the method signature. If we want to get rid of the closure, we need our method to return the value that we pass into the closure. Something like:

static func upload(image: UIImage) -> String

Now, when we create the method body, the compiler will say “Missing return in a function expected to return 'String'“.

This is fine. That’s what we’re aiming to fix with async/await. But how?

withUnsafeContinuation

We can think of withUnsafeContinuation as a wrapper that you use around your asynchronous code which blocks the thread until you explicitly resume. If you write tests for your asynchronous code, you should be familiar with this pattern from using XCTestExpectation and its fulfill method.

static func upload(image: UIImage) -> String {
    withUnsafeContinuation { continuation in // Compiler error 1: "'async' in a function that does not support concurrency"
        DispatchQueue.main.async {
            sleep(1) // Fake wait
            completion("fake URL") // Compiler error 2: "Cannot find 'completion' in scope"
        }
    }
}

So the compiler is not yet content. The second error is something we are familar with, but the first one is new: “'async' in a function that does not support concurrency“.

My developer instincts tell me to mark this function somehow to tell the compiler that it supports concurrency. Maybe make it more explicit that my function is… async.

So changing from method signature from

static func upload(image: UIImage) -> String

to

static func upload(image: UIImage) async -> String

actually works! Why did I put async there and not somewhere else in the signature? Well, maybe I tried different places until it doesn’t produce an error, who knows!

For the second error, “Cannot find 'completion' in scope“, I’m just going to go ahead and remove that line. Sometimes you just need to ignore your problems until they’re gone, right?

We have a new compiler error, “Call is 'async' but is not marked with 'await'” but it’s so easy to fix that even Xcode itself offers a solution. We just mark our call with await.

Here’s how our method looks now:

static func upload(image: UIImage) async -> String {
    await withUnsafeContinuation { continuation in
        DispatchQueue.main.async {
            sleep(1) // Fake wait
        }
    }
}

We just wrote a couple of lines and barely did what we wanted to, but our code compiles… Some things are missing, right? Like a puzzle. Let’s go one by one:

  1. Our method signature returns a String, but the method body doesn’t return anything yet it still compiles.

The answer is Swift 5.1, or more specifically, “Implicit returns from single-expression functions”. So our method actually does return something, and that is the result of the withUnsafeContinuation method. But maybe it’s a good idea to make return explicit to avoid confusion.

  1. In the original method, we would return a string using the completion block, here we just erased it and didn’t put anything else instead.

Fair point. But we can’t just return something in the body of DispatchQueue.main.async (“Unexpected non-void return value in void function“), so there must be a different way of doing that. Maybe calling a method?

  1. withUnsafeContinuation passes a value of type UnsafeContinuation into its closure but we never use it. What is it for?

There’s only one way to figure it out: To play with it. When we try to use it, we see that it has only one method available, which is continuation.resume(returning:). Could it be the method we were looking for in the previous problem?

Now we can finalize our method using continuation.resume(returning:). The complete version looks like this:

static func upload(image: UIImage) async -> String {
    return await withUnsafeContinuation { continuation in
        DispatchQueue.main.async {
            sleep(1) // Fake wait
            continuation.resume(returning: "fake URL")
        }
    }
}

Time to get a pulse-check. In the “sad” code above, we mentioned two problems so let’s refresh our memories and note down our progress:

  • Problem 1: Our method deals with asynchronous code so it cannot return anything. That’s why it takes a closure where it passes the result.

This is now fixed as the method returns a String in the signature and the method body is updated accordingly.

  • Problem 2: When we use the trailing closure syntax in the place we call this method and embed such methods within each other, things get out of control.

This is not yet fixed because we didn’t refactor the part we call this method, but it doesn’t take a closure anymore so we made good progress there.

It’s time to use our new method, so let’s scrap everything in startFlow() and just call this new method:

func startFlow() {
    let url = NetworkAPI.upload(image: UIImage(named: "an-image")!) // Compiler error: "'async' in a function that does not support concurrency"
}

Well, we are familiar with the compiler error but something different happens when we use Xcode suggestion to correct this: The method gets marked with @asyncHandler. Okay, our method is literally an async handler so the signature feels right, let’s leave it as it is. And the new error “Call is 'async' but is not marked with 'await'” is also easy to fix, we just mark our call with await and we have the following:

@asyncHandler func startFlow() {
    let url = await NetworkAPI.upload(image: UIImage(named: "an-image")!)
}

Everything seems to work. So, if we were to use the same syntax for our other methods, the final state of startFlow() would be something like this:

@asyncHandler func startFlow() {
    guard await PhotosAPI.grantPhotosAccess() else { return }
    let selectedPhoto = await PhotosAPI.selectPhoto()
    let uploadedFileUrl = await NetworkAPI.upload(image: selectedPhoto)
    let didSendUrlWithEmail = await NetworkAPI.sendUrlWithEmail(urlString: uploadedFileUrl)
    self.displayResultAlert(didSendEmail: didSendUrlWithEmail)
}

What do you think? Much cleaner, right? There’s one last thing we didn’t talk about, that is @asyncHandler.

@asyncHandler

We can think of @asyncHandler like a stamp you use in the method signature to tell the compiler that your method does not return anything but just handles other async functions. When you mark your method with @asyncHandler, you can use it in other methods without having to mark them with @asyncHandler or async. Consider @asyncHandler as the last wrapper in your async code because eventually, you need to call these methods from a method that you can’t touch the signature, for instance, from UIViewController overrides.

Final words

As a final recap, let’s see the code before async/await:

Here’s the code with async/await:

As you can see, the new code is almost no different than a synchronous code block but the code is more readable and more manageable compared to the one with closures, thanks to async/await. I hope this post helped you get familiar with how async/await works and you are as excited about the future of concurrency in Swift as I am. Feel free to leave a comment on this post or send me a tweet on Twitter.

Oh, and for the full code, check out my gist on Github.

References

Aligning SKPhysicsBody Correctly with SKShapeNode

When you want to create a circle in SpriteKit, SKShapeNode is the quickest and the simplest way for it. You don’t need to create images, you can manage the size, fill colour, stroke colours etc.

However, if you want this node to involve with collisions, you may get some trouble when creating an SKPhysicsBody for that node. The creating process is similar to SKSpriteNode but the alignment of it is different.

By default, SKShapeNode anchor points begin from (0, 0) and there isn’t any property to set it as we want. When we assign a SKPhysicsBody to this node, body’s anchor is its center point so the body doesn’t cover the node correctly.

Here’s how it looks when you want to implement for SKShapeNode as you do in SKSpriteNode:

skshapenode-skphysicsbody

There are plenty of people who were unable to solve this issue. Yet there is one answer on SO that helped me out with this.

To work around this situation, you can create an SKSpriteNode to implement the body and an SKShapeNode as the SKSpriteNode’s child to draw the shape.

First, create an SKSpriteNode and set the width and height same with the diameter of the circle

float radius = 30.0;
SKSpriteNode *aCircle = [SKSpriteNode spriteNodeWithColor:[UIColor clearColor] size:CGSizeMake(radius * 2, radius * 2)];

Then create a circular SKPhysicsBody for the SKSpriteNode (thankfully, this is possible)

SKPhysicsBody *circleBody = [SKPhysicsBody bodyWithCircleOfRadius:radius];
[circleBody setDynamic:NO];
[circleBody setUsesPreciseCollisionDetection:YES];
[aCircle circleBody];

Here is the key part. Create a CGPathRef as an ellipse in the rect with correct center values.

CGPathRef bodyPath = CGPathCreateWithEllipseInRect(CGRectMake(-[aCircle size].width / 2, -[aCircle size].height / 2, [aCircle size].width, [aCircle size].width), nil);
SKShapeNode *circleShape = [SKShapeNode node];
[circleShape setFillColor:[UIColor redColor]];
[circleShape setLineWidth:0];
[circleShape setPath:bodyPath];
[aCircle addChild:circleShape];
CGPathRelease(bodyPath);

Don’t forget to add the child to the scene then you are done. As you can see below, the physics body now matches the node frame correctly.

skspritenode-skshapenode-skphysicsbody.png

Source link of the answer:
SKPhysicsBody not as expected

Other questions about similar issues:
How to align SKPhysicsBody and SKShapeNode?
Align SKPhysicsBody with SKShapeNode
SKPhysicsBody does not work on SKShapeNode
SKshapenode is not responding to Physicsbody
how to make collisions with skshapenode circles
Keeping an SKShapeNode within the bounds of an SKSpriteNode

Vi Cheatsheet

a -> Append cursor (After position)
i -> Insert cursor (At position)
esc -> Remove cursor if active
:wq -> Save and quit
:q -> Ask to save and quit
:q! -> Quit without saving
dd -> Cut the line
yy -> Copy the line
p -> Paste the line
:n -> Go to line n
/text -> Search for ‘text’
n -> Jump to next match when search is active
0 -> Go to the beginning of the line
$ -> Go to the end of the line
G -> Go to the end of the document
yn + arrow down -> Copy the current line with next n lines
yn + arrow up -> Copy the current line with previous n lines

Gamification: http://vim-adventures.com (Even though it’s for vi not vim there shouldn’t be any major differences as mentioned here.)

Sample Apple Push Notification PHP Script

This is an old script that I used to use for sending notifications. I don’t remember the source, on the other hand, it has been modified a couple of times already.

Even though I could manage to send notifications with this script, the Apple server was rejecting the connection after the amount reaches more than 50. It was usually getting cut off around 70. So it needs to get some management for not sending in a loop, like threading or whatever.

<?php
 
// set time limit to zero in order to avoid timeout
set_time_limit(0);
 
// charset header for output
header('content-type: text/html; charset: utf-8');
 
// this is the pass phrase you defined when creating the key
$passphrase = 'my_secret_pass';
 
// you can post a variable to this string or edit the message here
if (!isset($_POST['msg'])) {
$_POST['msg'] = "Notification message here!";
}
 
// tr_to_utf function needed to fix the Turkish characters
$message = tr_to_utf($_POST['msg']);
 
// load your device ids to an array
$deviceIds = array(
'lh142lk3h1o2141p2y412d3yp1234y1p4y1d3j4u12p43131p4y1d3j4u12p4313',
'y1p4y1d3j4u12p43131p4y1d3j4u12p4313lh142lk3h1o2141p2y412d3yp1234'
);
 
// this is where you can customize your notification
$payload = '{"aps":{"alert":"' . $message . '","sound":"default"}}';
 
$result = 'Start' . '<br />';
 
////////////////////////////////////////////////////////////////////////////////
// start to create connection
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'MyAppGenerated.pem');
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
 
echo count($deviceIds) . ' devices will receive notifications.<br />';
 
foreach ($deviceIds as $item) {
    // wait for some time
    sleep(1);
     
    // Open a connection to the APNS server
    $fp = stream_socket_client('ssl://gateway.push.apple.com:2195', $err, $errstr, 60, STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT, $ctx);
 
    if (!$fp) {
        exit("Failed to connect: $err $errstr" . '<br />');
    } else {
        echo 'Apple service is online. ' . '<br />';
    }
 
    // Build the binary notification
    $msg = chr(0) . pack('n', 32) . pack('H*', $item) . pack('n', strlen($payload)) . $payload;
     
    // Send it to the server
    $result = fwrite($fp, $msg, strlen($msg));
     
    if (!$result) {
        echo 'Undelivered message count: ' . $item . '<br />';
    } else {
        echo 'Delivered message count: ' . $item . '<br />';
    }
 
    if ($fp) {
        fclose($fp);
        echo 'The connection has been closed by the client' . '<br />';
    }
}
 
echo count($deviceIds) . ' devices have received notifications.<br />';
 
// function for fixing Turkish characters
function tr_to_utf($text) {
    $text = trim($text);
    $search = array('Ü', 'Þ', 'Ð', 'Ç', 'Ý', 'Ö', 'ü', 'þ', 'ð', 'ç', 'ý', 'ö');
    $replace = array('Ãœ', 'Åž', '&#286;ž', 'Ç', 'Ä°', 'Ö', 'ü', 'ÅŸ', 'ÄŸ', 'ç', 'ı', 'ö');
    $new_text = str_replace($search, $replace, $text);
    return $new_text;
}
 
// set time limit back to a normal value
set_time_limit(30);

Use Sublime Text to Bulk Rename Your Files

There are two cool plugins: One is dired, which allows you to use Sublime Text to manage your files and folders; and another is Text Pastry, which helps you to put increasing numbers to the multi-selected cursors (Of course, it is more than that, just not in this case).

Go ahead and combine this two. Yes, giving numbered names to contents of a folder. There were (in fact, probably still are) utilities existed that people buy for. Why pay, when you can do it with plugins?

First, install dired and Text Pastry plugins from Sublime Text Package Control. No need to restart, just get into it directly by pressing Cmd+Shift+P -> dired: Goto Anywhere -> Goto Directory and then hit enter. It doesn’t matter what directory you are getting into since you can now navigate between folders thanks to dired.

Now, you can see the contents of the directory you are currently inside of, and you can see the shortcuts for navigation. Goto a directory that you want to bulk rename contents of and then press R. Now you can rename the files by using great abilities of Sublime Text such as locating matches, inserting multiple cursors and all.

bulk-rename-files-using-sublime-text-dired-and-text-pastry

Assume that you have a set of images that were taken during one of your trips and you want to rename them like -> trip_1.jpg, trip_2.jpg and so. You opened the folder in Sublime, selected all the images (lines), set all of the names to trip_.jpg and placed your multi cursors after _ (before .). Now what? Just hit Cmd+Shift+P again and then select Text Pastry: From 1 To X. That’s it. Now all of your files have numbers increased by 1 at the end of their names. Hit Ctrl+Enter to save changes and you’re good to go.

Important Note: Dired is no longer maintained so it will not appear on the package control. The developer was kind enough to share the latest working copy so I’ve uploaded it to Github. Install instructions can be found inside README.md. To download: https://github.com/kublaios/dired