Autoclosures And @autoclosure In Swift 3

What Is an Autoclosure

The first parameter of the fatalError(_:file:line:) function is an autoclosure as indicated by the @autoclosure keyword. But what is an autoclosure?

An autoclosure allows you to pass an expression to a function as an argument.

This definition should get us started. With this in mind, it makes sense that we can pass a string to the fatalError(_:file:line:) function. The string we pass to the function is an expression. The autoclosure wraps it in a closure. But why is that? What is the advantage of wrapping the expression in a closure?

By wrapping the expression in a closure, the function can decide if and when the closure is invoked. The moment the closure is invoked, the expression is evaluated.

As you can see, if used correctly, autoclosures are a powerful concept.

Anatomy of an Autoclosure

There are a few things you need to know about autoclosures. First, an autoclosure doesn’t take any parameters. Second, autoclosures usually return a value, but that isn’t always true. Later in this tutorial, we take a look at an example of an autoclosure that returns Void.

In Swift 3, closures are non-escaping by default. If the autoclosure of a function needs to be escaping, you need to prefix the @autoclosure attribute with the @escaping attribute.

When to Use Autoclosures

The benefit of autoclosures is that you don’t need to wrap the expression in curly braces. That is what you would need to do if you were to pass in a closure instead of an autoclosure.

In the below example, you can see that the fatalError(_:file:line:) function can accept an expression as its first argument thanks to autoclosures.

fatalError(response.error + " " + response.error)

Examples

Before I show you two examples of autoclosures, I need to emphasize that you won’t find yourself using autoclosures very often. This is a quote from The Swift Programming Language.

It’s common to call functions that take autoclosures, but it’s not common to implement that kind of function.

Despite the above quote, it is important that you understand the concept underlying autoclosures even though you won’t be implementing functions that use them very often.

Unbox

The first example I would like to show you is taken from one of my favorite libraries, Unbox, a lightweight JSON decoder created by John Sundell.

The following method is used to extract the value for a particular key or key path. What is important is that the method takes an autoclosure as its third parameter. The autoclosure returns the fallback value if no value for a particular key or key path is found.

func resolveRequiredValueForKey<R>(key: String, isKeyPath: Bool, fallbackValue: @autoclosure () -> R, transform: (T) -> R?) -> R {
    if let value = self.resolveOptionalValueForKey(key: key, isKeyPath: isKeyPath, transform: transform) {
        return value
    }
    
    self.unboxer.failForInvalidValue(invalidValue: self.unboxer.dictionary[key], forKey: key)
    
    return fallbackValue()
}

The implementation isn’t too complicated. What is of interest to us is the last line of the method.

return fallbackValue()

If no value was found, the autoclosure is invoked and the fallback value, which could be the result of an expression, is returned.

View Animations

The second example is a clever concept created by none other than Erica Sadun. In a blog post, Erica writes that autoclosures can help make the UIView API for animations easier and more elegant.

She wants to go from this:

UIView.animate(withDuration: 2.5) { 
    self.view.backgroundColor = .orange
}

To this:

UIView.animate(withDuration: 2.5, self.view.backgroundColor = .orange)

Notice that we don’t need to wrap the expression in a closure. How does this work?

To make this possible, we create an extension for UIView and implement a class method that accepts an autoclosure.

extension UIView {

    class func animate(withDuration duration: TimeInterval, _ animations: @escaping @autoclosure () -> Void) {
        UIView.animate(withDuration: duration, animations: animations)
    }

}

Remember that closure parameters, including autoclosures, are non-escaping by default. This means we need to prefix the @autoclosure attribute with the @escaping attribute.

What do you think? Doesn’t this look better?

UIView.animate(withDuration: 2.5, self.view.backgroundColor = .orange)

Should You Use Autoclosures

Apple emphasizes that autoclosures should not be overused. Not only is it hard to find valid use cases, autoclosures also make it harder to understand the program flow. Don’t overcomplicate your code with autoclosures if there is an easier alternative.

Autoclosures And @autoclosure In Swift 3

Dynamic Keyword in Swift 3

You probably know that the Swift language defines a number of attributes, such as objc, escaping, and available. It also defines a range of declaration modifiers.

As the name implies, a declaration modifier modifies a declaration. For example, by marking a class declaration with the final keyword, we inform the compiler that the class cannot be subclassed. This allows the compiler to make a number of optimizations to increase performance.

One other declaration modifier you may have come across is dynamic. In this tutorial, we explore what the meaning is of the dynamic declaration modifier and when you may want or need to use it.

Swift and Objective-C Interoperability

Even though Swift and Objective-C play well together, not every feature of Objective-C is available in Swift. Objective-C is a powerful language and much of that power is the result of the Objective-C runtime. Dynamic dispatch, for example, is one of the features that make Objective-C as dynamic as it is.

Dynamic what? Dynamic dispatch. It simply means that the Objective-C runtime decides at runtime which implementation of a particular method or function it needs to invoke. For example, if a subclass overrides a method of its superclass, dynamic dispatch figures out which implementation of the method needs to be invoked, that of the subclass or that of the parent class. This is a very powerful concept.

Swift uses the Swift runtime whenever possible. The result is that it can make a number of optimizations. While Objective-C solely relies on dynamic dispatch, Swift only opts for dynamic dispatch if it has no other choice. If the compiler can figure out at compile time which implementation of a method it needs to choose, it wins a few nanoseconds by opting out of dynamic dispatch.

Why Do I Need to Know This?

If you really want to understand what the dynamic declaration modifier means, then you need to understand the above.

How the Swift runtime works isn’t the topic of this tutorial. But you need to understand that the Swift runtime chooses other options, such as static and virtual dispatch, over dynamic dispatch whenever possible. It does this to increase performance.

Static and virtual dispatch are much faster than dynamic dispatch. Even though we are talking nanoseconds, the net result can be dramatic. If you are wondering, inlined access beats static and virtual dispatch hands down.

As you can imagine, bypassing dynamic dispatch has some drawbacks. Dynamic dispatch is one of the ingredients that make the Objective-C runtime as powerful as it is.

Right. But I am only using Swift in my project. Are you? The frameworks that power iOS, tvOS, macOS, and watchOS applications are written in Objective-C. And many features we have come accustomed to are only possible because of the dynamic Objective-C runtime, including Core Data and Key-Value Observing.

Dynamic Dispatch

This is a long explanation for a simple answer. By applying the dynamic declaration modifier to a member of a class, you tell the compiler that dynamic dispatch should be used to access that member.

By prefixing a declaration with the dynamic keyword, the declaration is implicitly marked with the objc attribute. The objc attribute makes the declaration available in Objective-C, which is a requirement for it to be dispatched by the Objective-C runtime.

You should now understand why the lengthy introduction was important for understanding the meaning of the dynamic keyword.

Classes Only

It goes without saying that the dynamic declaration modifier can only be used for members of a class. Structures and enumerations don’t support inheritance, which means the runtime doesn’t have to figure out which implementation it needs to use.

When to Use It

The dynamic declaration modifier is required whenever you need to make use of Objective-C’s dynamism.

Dynamic Keyword in Swift 3

@escaping, @available In Swift 3

In Swift 2, you may have run into the @noescape attribute. Have you ever taken the time to understand what it means? In Swift 3, @noescape has been removed from the language. Why is that? And why does Swift 3 introduce @escaping? Answering these questions is the focus of this article.

What Is the Meaning Of @noescape?

Even though @noescape is deprecated in Swift 3, it is useful to understand what it means. Why is that? The answer is simple. The @noescape attribute is applied by default in Swift 3. Let us start form the beginning.

What Is an Escaping Closure?

You first need to understand what an escaping closure is. The definition is very simple and easy to understand. If a closure is passed as an argument to a function and it is invoked after the function returns, the closure is escaping. It is also said that the closure argument escapes the function body. With this definition in mind, the name of the term escaping closure is well chosen. Right?

If a closure is passed as an argument to a function and it is invoked after the function returns, the closure is escaping.

In Swift 2, you could mark a function parameter with the @noescape attribute, telling the compiler that the closure passed to the function is not allowed to escape the function body. Take a look at the following example. Note that this example is written in Swift 2.

import HealthKit

class HealthKitManager: NSObject {

    private let healthStore = HKHealthStore()

    func requestAuthorization(completion: (Bool, NSError?) -> Void) {
        var shareTypes = Set<HKSampleType>()
        var readTypes = Set<HKSampleType>()

        // Add Workout Type
        shareTypes.insert(HKSampleType.workoutType())
        readTypes.insert(HKSampleType.workoutType())

        // Request Authorization
        healthStore.requestAuthorizationToShareTypes(shareTypes, readTypes: readTypes, completion: completion)
    }

}

You can see that the requestAuthorization(_:) function accepts one parameter, a closure. In Swift 2, closures can by default escape the function body and that is why the above example doesn’t cause the compiler any issues. Note that the completion parameter is passed as an argument to the requestAuthorizationToShareTypes(_:readTypes:completion:) method of HKHealthStore. This method is asynchronous, which means the closure is invoked after requestAuthorization(_:) returns. In other words, the closure we pass to requestAuthorization(_:) is escaping. It escapes the function body of requestAuthorization(_:).

Things become interesting if we add the @noescape attribute to the parameter of requestAuthorization(_:). This is what the example looks like with the @noescape attribute.

import HealthKit

class HealthKitManager: NSObject {

    private let healthStore = HKHealthStore()

    func requestAuthorization(@noescape completion: (Bool, NSError?) -> Void) {
        var shareTypes = Set<HKSampleType>()
        var readTypes = Set<HKSampleType>()

        // Add Workout Type
        shareTypes.insert(HKSampleType.workoutType())
        readTypes.insert(HKSampleType.workoutType())

        // Request Authorization
        healthStore.requestAuthorizationToShareTypes(shareTypes, readTypes: readTypes, completion: completion)
    }

}

We explicitly tell the compiler that the completion parameter should not be allowed to escape the function body. The result is that the compiler throws an error, explaining what is wrong.

Swift 3

Let me show you what the above example looks like in Swift 3. This will show you what has changed and what you need to know about escaping closures in Swift 3.

import HealthKit

class HealthKitManager: NSObject {

    private let healthStore = HKHealthStore()

    func requestAuthorization(@noescape completion: (Bool, Error?) -> Void) {
        var shareTypes = Set<HKSampleType>()
        var readTypes = Set<HKSampleType>()

        // Add Workout Type
        shareTypes.insert(HKSampleType.workoutType())
        readTypes.insert(HKSampleType.workoutType())

        // Request Authorization
        healthStore.requestAuthorization(toShare: shareTypes, read: readTypes, completion: completion)
    }
    
}

The compiler immediately informs us that @noescape is the default in Swift 3 and suggests to remove @noescape. In fact, @noescape is deprecated and you should no longer use it in Swift 3.

Because the closure we pass to requestAuthorization(completion:) (note that the method signature is different in Swift 3) is escaping, we need to mark the parameter as escaping. We use a new attribute for this, @escaping. This is a direct result of SE–0103, a Swift evolution proposal that proposes to make non-escaping closures the default. This is a very welcome change if you ask me.

import HealthKit

class HealthKitManager: NSObject {

    private let healthStore = HKHealthStore()

    func requestAuthorization(completion: @escaping (Bool, Error?) -> Void) {
        var shareTypes = Set<HKSampleType>()
        var readTypes = Set<HKSampleType>()

        // Add Workout Type
        shareTypes.insert(HKSampleType.workoutType())
        readTypes.insert(HKSampleType.workoutType())

        // Request Authorization
        healthStore.requestAuthorization(toShare: shareTypes, read: readTypes, completion: completion)
    }
    
}

You may have noticed that the @escaping attribute precedes the type of the parameter, not the name. This too is new in Swift 3.

What Is the Meaning of @escaping?

This brings us to the meaning of the @escaping attribute. Because closures are by default non-escaping in Swift 3, escaping closures need to be marked as such. And the @escaping attribute lets us do that.

The error of the compiler disappears by marking the closure as escaping, using the @escaping attribute.

Why Is This Important?

There are several benefits to make closures non-escaping by default. The most obvious benefits are performance and the ability for the compiler to optimize your code. If the compiler knows that a closure is non-escaping, it can take care of many of the nitty-gritty details of memory management.

This also means that you can use the self keyword without issues in non-escaping closures because the closure is invoked before the function returns. There is no need to use a weak reference to self in the closure. This is a nice benefit you get for free.

@AVAILABLE

In iOS 8, Apple changed the APIs for working with notification settings. If you are working on an application that supports an earlier version of iOS, then you are forced to use the deprecated APIs for registering for remote notifications. Fortunately, Swift makes this easy and safe.

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    if #available(iOS 8.0, *) {
        // Create User Notification Settings
        let userNotificationSettings = UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)

        // Register User Notification Settings
        application.registerUserNotificationSettings(userNotificationSettings)

    } else {
        // Register for Remote Notification Type
        application.registerForRemoteNotifications(matching: [.alert, .badge, .sound])
    }

    return true
}

The syntax is clear and concise. You use #available followed by a comma separated list of platform names and versions. The asterisk at the end of the list is required. It is a placeholder for future platforms.

How You Can Use It?

The availability syntax only works if the APIs you are using support it. Fortunately, it is easy to add support to your own libraries for the availability syntax.

In the example below, we use the @available attribute to indicate that the CircularView class is only available on iOS 8 and higher.

import UIKit

@available(iOS 8.0, *)
class CircularView: UIView {

    @available(iOS 8.0, *)
    func someMethod() {
        ...
    }

    @available(iOS 9.0, *)
    func anotherMethod() {
        ...
    }
    
}

You can use the @available attribute for any symbol, including classes, structures, enumerations, and methods. Nesting is important, though. For example, a method of a class cannot be more available than the class itself. In the above example, the compiler will throw an error if we set the availability of someMethod() to iOS 7.0.

At the time of writing, the availability syntax supports iOS, OS X, tvOS, and watchOS, including extensions for these platforms.

  • iOS
  • iOSApplicationExtension
  • OSX
  • OSXApplicationExtension
  • tvOS
  • tvOSApplicationExtension
  • watchOS
  • watchOSApplicationExtension
@escaping, @available In Swift 3