WWDC24 SALE: Save 50% on all my Swift books and bundles! >>

Key points

There are three pieces of code I’d like to revisit briefly, just to make sure you understand them fully.

First, I want to look more closely at how closure capturing works with asyncAfter(). Here’s some code as an example:

DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [unowned self] in

The call to asyncAfter() needs two parameters, but we pass the second one in using trailing closure syntax because it’s clearer. The first parameter is specified as a DispatchTime value, which is the exact time to execute the code. When we specify .now(), Swift is smart enough to realize that means DispatchTime.now(), which is the current time. It then lets us add 1 second to it, so that the finished deadline ends up being one second away from now.

Then there’s the [unowned self]. This is called a capture list, and it gives Swift instructions how to handle values that get used inside the closure. In this case, self.doStuff() references self, so the capture list [unowned self] means “I know you want to capture self strongly so that it can be used later, but I want you not to have any ownership at all.”

If the closure runs and self has become nil for some reason, the call to self.doStuff() will crash: we told Swift not to worry about ownership, then accidentally let self get destroyed, so the crash is our own fault. As an alternative, we could have written [weak self], which would capture self in the closure as an optional. With that change, you’d need to run this code instead:


Closure capturing can be a complicated topic. In this case, [unowned self] isn’t really even needed because there’s no chance of a reference cycle: self doesn’t own DispatchQueue.main, so the reference will be destroyed once the closure finishes. However, there’s no harm adding [weak self], which is why I often include it.

The second piece of code I’d like to review is this, taken from project 15:

UIView.animate(withDuration: 1, delay: 0, options: [], animations: {
    switch self.currentAnimation {
    case 0:

}) { finished in
    sender.isHidden = false

At this point in your Swift career you’ve seen several functions that accept closures, but this one takes two: one is a set of animations to perform, and one is a set of actions to run when the animations have completed. I didn’t include closure capturing here because it isn’t needed – the animation closure will be used once then destroyed.

I don’t want to sound like a broken record, but: if you use [weak self] when it isn’t needed, nothing happens. But if you don’t use it and it was needed, bad things will happen - at the very least you’ll leak memory.

The final piece of code to review is this, also taken from project 15:

self.imageView.transform = CGAffineTransform(rotationAngle: CGFloat.pi)
self.imageView.transform = CGAffineTransform.identity

There are a few things in there that I’d like to recap just briefly:

  1. The self is required when accessing imageView, because we’re inside a closure and Swift wants us to explicitly acknowledge we recognize self will be captured.
  2. The CGFloat.pi constant is equal to 180 degrees, and it also has equivalents in Float.pi and Double.pi – this is just to save you having to typecast values.
  3. The identity matrix, CGAffineTransform.identity, has no transformations: it’s not scaled, moved, or rotated, and it’s useful for resetting a transform.
Save 50% in my WWDC sale.

SAVE 50% To celebrate WWDC24, all our books and bundles are half price, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

Buy Pro Swift Buy Pro SwiftUI Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Beyond Code

Was this page useful? Let us know!

Average rating: 4.9/5

Unknown user

You are not logged in

Log in or create account

Link copied to your pasteboard.