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
self.doStuff()
}
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:
self?.doStuff()
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:
break
default:
break
}
}) { 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:
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.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.CGAffineTransform.identity
, has no transformations: it’s not scaled, moved, or rotated, and it’s useful for resetting a transform.SPONSORED Ready to dive into the world of Swift? try! Swift Tokyo is the premier iOS developer conference will be happened in April 9th-11th, where you can learn from industry experts, connect with fellow developers, and explore the latest in Swift and iOS development. Don’t miss out on this opportunity to level up your skills and be part of the Swift community!
Sponsor Hacking with Swift and reach the world's largest Swift community!
Link copied to your pasteboard.