Every now and then, I take some time out of my day to explore something about the Swift language that I don't know yet. There is a lot left to explore. I document my findings in a series I named What The Swift. If you are curious about the more subtle details of the Swift language, then this series is for you.

If you've spent some time writing Swift, then you've probably come across a variable, constant, or parameter of type AnyObject. And you know what AnyObject is. Right? Don't worry. You're not alone. Let's take a look and dive into the bowels of the Swift standard library to find out.

Get Your Hands Dirty

Fire up Xcode and create a new playground. Choose the Blank template from the iOS section.

Setting Up the Playground

Name the playground What The Swift, tell Xcode where you'd like to save the playground, and click Create.

Setting Up the Playground

Exploring the Swift Standard Library

Clear the contents of the playground and declare a variable, myObject, of type AnyObject.

var myObject: AnyObject

If you pay close attention, you can see a first clue. Take a look at Xcode's autocompletion suggestions when you type AnyObject.

AnyObject is a protocol.

Did you notice the letter T on the left? Xcode's autocompletion menu shows us that AnyObject is a type. That isn't surprising. But there's more. Xcode also tells us that AnyObject is a protocol to which all classes implicitly conform. That's a start. Let's dive into the bowels of the Swift standard library to learn more about the AnyObject protocol.

Press Command and click AnyObject to navigate to the interface of the AnyObject protocol. There isn't a lot of code to explore. AnyObject is defined as a public type alias.

public typealias AnyObject

More interesting are the comments above the definition. The comments are very telling and answer some of the questions you might have.

The protocol to which all classes implicitly conform.

This summarizes what the AnyObject protocol is and what you need to know about it. Every class implicitly conforms to the AnyObject protocol. That's an interesting statement. But what does it mean? And why is that useful or important? Let's revisit the example we added to the playground earlier.

var myObject: AnyObject

Because the myObject variable is of type AnyObject, we know that the value stored in myObject is an instance of a class. And that's also what the comments of the AnyObject protocol tell us.

You use AnyObject when you need the flexibility of an untyped object or when you use bridged Objective-C methods and properties that return an untyped result. AnyObject can be used as the concrete type for an instance of any class, class type, or class-only protocol.

If you're familiar with Objective-C, then you've most likely come across the id keyword. The id type is used to point to an Objective-C object. The AnyObject protocol is similar and it helps bridge the gap between Swift and Objective-C. The Swift standard library confirms this.

The flexible behavior of the AnyObject protocol is similar to Objective-C's id type. For this reason, imported Objective-C types frequently use AnyObject as the type for properties, method parameters, and return values.

Downcasting AnyObject

The AnyObject protocol seems to add a bit of flexibility to the Swift language. But we need to pay a small price for that flexibility. A class instance of type AnyObject isn't always what you need or want. Take a look at this example.

class Person {

    var first: String = ""
    var last: String = ""

}

let myPerson: AnyObject = Person()

We define a class, Person, with two variable properties of type String, first and last. We create an instance of the Person class and assign it to the myPerson constant. Even though the compiler can infer the type of the myPerson constant, we explicitly declare myPerson as AnyObject. The compiler doesn't complain since the Person class implicitly conforms to the AnyObject protocol.

We also learned that AnyObject can be used as the concrete type for an instance of any class, class type, or class-only protocol. But remember that AnyObject is a protocol, not a class type.

Even though the example is a bit contrived, it illustrates why the AnyObject protocol can be inconvenient to use. Because myPerson is of type AnyObject, we cannot access the first and last properties of the Person instance.

Downsides of AnyObject

Despite myPerson being of type AnyObject, it remains a Person instance. This is how the Swift standard library phrases this.

Objects with a concrete type of AnyObject maintain a specific dynamic type and can be cast to that type using one of the type-cast operators (as, as?, or as!).

To access the properties and methods of the Person instance, we need to downcast myPerson to a Person instance. This means we type cast myPerson to the Person type using a downcast operator. In this example, we use optional binding and the conditional downcast operator to safely downcast myPerson to the Person type.

class Person {

    var first: String = ""
    var last: String = ""

}

let myPerson: AnyObject = Person()

if let person = myPerson as? Person {
    person.first
    person.last
}

Because the person constant is of type Person, we can access the first and last properties of the Person instance. Always remember that a downcast operation can fail. That's why the conditional downcast operator returns an optional.

The AnyObject protocol is also useful to bridge the gap between Swift and Objective-C. Some Objective-C APIs use the AnyObject protocol to provide compatibility with Swift.

What The Swift

I hope this exploration has taught you more about the AnyObject protocol, what it is, and what it can be used for. Next time you encounter a variable, constant, or parameter of type AnyObject you know what it is and how to handle it.