NEW: My new book Pro SwiftUI is out now – level up your SwiftUI skills today! >>

Returning closures from functions

Paul Hudson    @twostraws   

Updated for Xcode 14.2

Functions can return strings, integers, arrays, and more, and because Swift lets us use closures anywhere we can also return closures from functions. But why would you want to do this – is it actually a reasonable thing to want to do?

The most common situation is effectively this: I need a function to call, but I don’t know what that function is. I know how to find out that function – I know who to ask to find the function – but I don’t know myself.

For example, I want to generate lots of random numbers, but I don’t know what algorithm to use. All I know is that if I call makeRandomGenerator() I’ll get back a function I can call that will generate a new random number every time I call it.

This behavior means we don’t need to know what the actual random number generator does, or how it was created. Behind the scenes we might get sent the same closure each time or perhaps a different closure; we don’t care. Without this, we’d need to type the precise name of the function everywhere we wanted to use it.

That leads to a second benefit: we can change our mind whenever we want, just by changing the function that creates the random number generator. All the places that call the function won’t change, because they still call makeRandomGenerator(). And all the ways they use the returned random number generator won’t change, because it’s just a closure that somehow returns a random number every time it’s called.

So, if you want to change the generator to a “fair” algorithm – where each number is generated an equal number of times, in a random order – then you just change the returned closure in makeRandomGenerator(). Or if you want to change it to have a Gaussian distribution, which means you get a bell curve where numbers in the middle of your range are returned more commonly than numbers towards the end of your range, then again you just change the returned closure – everywhere you use it remains absolutely unchanged.

I want to give you a little example of how this looks, because Swift actually comes with a built-in random number generator. It looks like this:

print(Int.random(in: 1...10))

That will print a number from 1 through 10.

If we wanted to write a function that returned one random number between 1 and 10, we would write this:

func getRandomNumber()-> Int {
    Int.random(in: 1...10)

That will return a random integer every time it’s called, so we can use it like this:


Now let’s go a step further: we’re going to make a function that returns a closure that, when called, will generate a random number from 1 through 10:

func makeRandomGenerator() -> () -> Int {
    let function = { Int.random(in: 1...10) }
    return function

Notice that our return type is now () -> Int, which means “a closure that takes no parameters and returns an integer.” Then, inside the function, we create a closure that wraps Int.random(in: 1...10) and send back that closure.

We can now use makeRandomGenerator() like this:

let generator = makeRandomGenerator()
let random1 = generator()

Again, the flexibility here is that all our code can call makeRandomGenerator() to be sent back some sort of code that can generate a random number. It doesn’t have to care what it does; we only care that it generates a new number every time it’s called.

If you’re finding closure syntax hard to remember, you’ll be pleased to know there’s a site just for you:

Hacking with Swift is sponsored by Essential Developer

SPONSORED From March 20th to 26th, you can join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer!

Click to save your free spot now

Sponsor Hacking with Swift and reach the world's largest Swift community!

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: 3.8/5

Unknown user

You are not logged in

Log in or create account

Link copied to your pasteboard.