Using closures in Swift 2 ways

I’m starting to learn Swift for iOS development and have been experimenting with closures which are using heavily within the various iOS libraries (if you want to learn more on how closures work in Swift I recommend reading the Swift book section on closures as a starting point. As always there is more than one way to skin a cat so here are two ways to use closures:

Passing as a function argument

The usual way is to pass the closure as a regular function argument. Here is a sample function definition:

func authorizeHealthKit(completion: ((success:Bool, error:NSError?) -> Void))

You could either assign a closure to variable or just include the closure inline as part of the function call:

// define the variable
let completion:(authorized:Bool, error:NSError?) -> Void = { (authorized:Bool, error:NSError?) -> Void

    in

        if authorized {
            debugPrint("HealthKit authorization received.")
        }
        else
        {
            debugPrint("HealthKit authorization denied!")
            debugPrint("(error)")
        }
    }

// now lets pass the completion to the function
healthKitManager.authorizeHealthKit(completion)

Here it seemed better to assign the closure to a variable because of the length of the closure body. There is nothing wrong with this but there is a better way.

As a trailing closure

Swift has a nice syntactic option for when you’re going to include a long closure as a parameter to a function. It has to be the last (or only) parameter.

Here is the same call to authorizeHealthKit that we used above but with a trailing closure:

healthKitManager.authorizeHealthKit() { (authorized,  error) -> Void in
        if authorized {
            debugPrint("HealthKit authorization received.")
        }
        else
        {
            debugPrint("HealthKit authorization denied!")
            debugPrint("(error)")

        }
    }

In the case that the closure is the only parameter to the function you can even leave off the parentheses:

// no parens!
healthKitManager.authorizeHealthKit { (authorized,  error) -> Void in
        if authorized {
            debugPrint("HealthKit authorization received.")
        }
        else
        {
            debugPrint("HealthKit authorization denied!")
            debugPrint("(error)")

        }
    }

Lets take a look at another example that takes multiple parameters:

func requestAuthorizationToShareTypes(_ typesToShare: Set<HKSampleType>?,readTypes typesToRead: Set<HKObjectType>?,completion completion: (Bool,NSError?) -> Void)

This comes straight from the HealthKit API and is a method in the HKHealthStore class.

We could call this by assigning the closure (“completion”) to a variable as we did up above but we can also call it by using the trailing closure feature since the closure is the last parameter to the function:

healthKitStore.requestAuthorizationToShareTypes(nil, readTypes: healthKitTypesToRead) { (success, error) -> Void in

        completion(success:success,error:error)
    }

Here the first parameter is a Set of types we want to be able to write to the Health database. In this case we don’t want to write any values. The second parameter is a Set of types we want to read from the Health database. (something along the lines of):

let healthKitTypesToRead: Set<HKObjectType>? = [HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeartRate)!]

The third parameter is our closure and here we are using the trailing closure option.

As a new Swift developer I’m still a bit torn on which way to use but I’m pretty much leaning toward doing trailing closures where possible. I assume this is the “right way” to do it in Swift these days.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: