Any And AnyObject Explained In Swift
How do you use Any
in Swift? What’s the difference between Any
and AnyObject
? And when and why should you use them? We’ll answer those questions in this tutorial.
Here’s what we’ll get into:
- What
Any
is and why it’s quite useful - The difference between
AnyObject
andAny
- Where
AnyObject
actually comes from
Ready? Let’s go.
- What’s “Any” In Swift?
- Why Use Any And AnyObject?
- The Difference Between Any And AnyObject
- Further Reading
What’s “Any” In Swift?
The Swift Programming Language provides two nonspecific types called Any
and AnyObject
. They’re nonspecific, because they really can be anything…
Let’s make a quick comparison. Consider that a constant called age
has value 42
and is of type Int
, like this:
let age:Int = 42
This type Int
is specific – we’re very clear here about the fact that age
is an integer number.
Now let’s check out a nonspecific type that uses Any
. The following code defines a values
array of type [Any]
:
let values:[Any] = ["Apple", 99, "Zaphod", -1]
What’s going on here? It doesn’t make sense at first glance – how can the values
array contain multiple different types, such as Int
and String
? That’s because the type of the values
array is nonspecific, it is [Any]
or array-of-Any
.
Making matters more mind-boggling, the individual items in values
still use their own specific types. Here, check this out:
for value in values
{
switch value {
case is String:
print("\(value) is a string!")
case is Int:
print("\(value) is an integer!")
default:
print("I don't know this value!")
}
}
In the above code, we’re using a for loop to iterate over the items in the values
array. For every item we’re executing a switch block. This switch block matches the type of value
with one of three cases, using the type checking is
keyword. In essence, we’re checking the type of each of the items in array
, and writing some text based on this type.
But why aren’t the types Any
? After all, the type of the values
array is [Any]
, so its items must have type Any
. Right? Well… yes and no. Here’s how:
- The type of the array
values
is[Any]
– it’s nonspecific - The types of the individual array items are specific, they’re still their own types, such as
Int
andString
Why would you use Any
with this approach? Let’s find out…
If you’re unfamiliar with type casting, now’s a good time to read up on that. Type casting, Any
and AnyObject
are closely related, because you’ll almost always want to type cast a variable or constant with type Any
or AnyObject
to a specific value type (such as in the above example).
Why Use Any And AnyObject?
The previous example begs the question: why would you want to use Any
in the first place? (We’ll get to AnyObject
later.)
Before we answer that question, consider that Swift has a few programming features that make dealing with types more flexible. For example:
- Optionals let you deal effectively with values that are “empty” or not
- Generics help you to create variables, functions, placeholders etc. that can deal with flexible types
- Protocols help you to flexibly define constraints for particular types, regardless of what type adopts them
Consider that programming is often nothing more than taking some input, processing it, and providing that as output. You’re writing code that downloads tweets from an API, manipulates that data, and shows it to a user in a UI.
It then makes sense for the Swift programming language to provide tools and features that make dealing with data easier. Optionals, generics, protocols, type casting, Any
and AnyObject
– all of those “tools” help you process data more effectively. And they (usually) make your code clearer, more expressive, and easier to extend and maintain.
Any
and AnyObject
are particularly useful for values that have mixed, nonspecific types. Consider, for example the following dictionary:
let tweet:[String: Any] = [
"text": "Lorem ipsum dolor amet hoodie bicycle rights, 8-bit mixtape",
"likes": 42,
"retweets": ["@reinder42", "@aplusk", "@beeblebrox"]
]
See how this dictionary mixes values of different types? The first value is a string, the second an integer, and the third an array of strings.
What if you want to get to specific values in the tweet
dictionary? Here’s how you do that:
if let likes = tweet["likes"] {
print("This tweet has \(likes) likes!")
}
In the above code, the constant likes
has type Int
. The code uses optional binding to get the value by its key. If needed, you can also make the type cast explicit, like this:
if let likes = tweet["like"] as? Int { ...
Thanks to Any
we can combine these different tweet
values in one dictionary. We don’t need a custom class or type for the tweet, or use multiple values and dictionaries. And that’s super useful!
The Difference Between Any And AnyObject
So far we’ve only looked at Any
. How is Any
different from its close cousin, AnyObject
?
Here’s what the official Swift documentation says:
-
Any
can represent an instance of any type at all, including function types -
AnyObject
can represent an instance of any class type
Simple enough, right? You use Any
for anything and AnyObject
for classes. But… there’s more!
First, it’s important to understand the difference between value types and reference types. In short, a value type is copied when you pass it around in your code, and a reference type is not. Classes are reference types, and passing those around in your code merely creates a reference to the original object.
This has a clear consequence:
- When you change a passed value type, the original value does not change
- When you change a passed reference type, the original value does change
Second, it’s crucial to understand the role of Objective-C, Swift’s predecessor, in Any
vs. AnyObject
. In Objective-C you can use the polymorphic, untyped id
pointer to refer to any kind of object. Much like Any
and AnyObject
in Swift.
In Objective-C, all objects are reference types†. They’re accessed via pointers, and Objective-C doesn’t have the concept of a value type. This is an important point!
One of the great features of Swift is its interoperability with Objective-C. You can use Objective-C code in Swift projects and vice-versa. And you can use SDKs written in Objective-C in your Swift projects. Neat!
This interoperability relies on bridging Swift types and Objective-C types, among other things. The Objective-C type NSString
, for example, is bridged to the Swift type String
. As a result, you can (almost) seamlessly work with strings between the two languages.
In Swift 2 and earlier, importing to Swift from Objective-C had a problem. Before Swift 3, Objective-C’s id
type was imported as AnyObject
. Any value of type id
that’s passed from Objective-C to Swift had the AnyObject
type in Swift.
Remember that AnyObject
can only works with classes? This implies that AnyObject
is a reference type. Objective-C doesn’t have value types, and id
is a reference type, because it uses pointers. And that has a huge disadvantage: you can’t benefit from Swift’s value types when interoperating with Objective-C’s id
.
Simply said, importing Objective-C’s id
into Swift as AnyObject
means you can’t benefit from value types in Swift. And that’s where Any
comes in.
Since Swift 3, Objective-C’s id
is now imported as Any
in Swift. This change is more complex than what’s described here – because it affected bridged and unbridged value types, generics, and collections with AnyHashable
.
But where does that leave the difference between Any
and AnyObject
? You hopefully felt this coming! Here we go:
-
Any
is used for both value and reference types, such as structs,Int
,String
, etc. and can also be used for classes, functions and closures -
AnyObject
is used for reference types, i.e. classes
When should you choose one or the other? It’s a good practice to use AnyObject
when working with classes, and Any
when working with value types.
As we’ve seen in the previous examples, an array with integers and strings should use Any
because they’re value types. You can use Any
with classes, but it’s better to use AnyObject
.
In any case, don’t use Any
when you don’t want to provide a value’s type. It’s important to only use Any
and AnyObject
when you explicitly need the behavior and functionality they provide. Otherwise you’re just creating needless ambiguity in your code!
Note: Some blogs, articles and forums still mention Objective-C’s id
as being imported as AnyObject
in Swift. This is outdated information.
† With the exception of NSString
, NSNumber
, etc. because they define object equality as something different than pointer equality.
Further Reading
Swift’s Any
type proves useful when you want to work with nonspecific types, for example in arrays and dictionaries.
In this tutorial, we’ve discussed the difference between Any
and AnyObject
and why that’s relevant for iOS developers today. And we’ve seen how type casting can be used to effectively work with Any
.
Want to learn more? Check out these resources: