Any vs AnyObject vs NSObject in Swift 3

What is the difference between these three enigmatic types? A sometimes confusing topic, and to confuse things further Swift 3 has shaken it up by removing implicit bridging between Foundation and native data types. Aagh!

Let’s look at the current situation with a good old Venn diagram:

AnyAnyObject

Let’s take a closer look at distinguishing these types with an example using arrays.

You probably know Swift is a type-safe language. For this reason, the compiler won’t permit you to type infer an array of different types that don’t share a common root:

//Error: Type of expression is ambiguous without more context
var test = ["a",0]

Strings and Ints in Swift don’t share a common root, so the compiler doesn’t know what you want it to do when type inferring the array.

There are three tricks for removing this error:

Solution 1: Array of NSObjects

If you import UIKit and cast the string as an NSString and the Int as an NSNumber the error goes away. Why?

import UIKit
//No error, test inferred to be [NSObject]
var test =  ["a" as NSString,0 as NSNumber]

UIKit Framework includes the Foundation framework. If you have imported the Foundation framework you can explicitly bridge common Swift data types to their Foundation Objective-C counterparts. (this bridging was automatic pre-Swift 3) String for example, bridges to NSString and Int can bridge to NSNumber.
Unlike in Swift, in Objective-C, most data types do have a root: NSObject is an actual class (docs here), that is the root of most classes if you’re using the Foundation framework.

If you option-click on the test variable, you’ll find that it has defaulted to [NSObject].

But then – out of curiosity – what happens if you add another variable to the array that does not have NSObject as a root, such as a class of your own?

class Test {}
//Error
var test = [Test(),"a" as NSString,0 as NSNumber]

The compiler can no longer find a root class to infer the array’s data type. You would need a way to indicate to the compiler that you know that the elements of the array are incompatible, and you’re ok with that.

Solution 2: NSArray

One solution would be to type the array as Foundation data type NSArray. NSArray is less strict than its Swift countertype; NSArray doesn’t enforce that elements it contains are the same data type.

//No error: test defined as NSArray
var test:NSArray =  [Test(), "a",0]

Solution 3: [Any] or [AnyObject]

If you specifically define the array as [Any], you are indicating to the compiler that you are aware that the elements are not of the same data type, and you are ok with that.

class Test {}
//No error, test is defined as [Any]
var test:[Any] = [Test(),"a",0]

You may be surprised to learn that unlike NSObject, Any is not actually a concrete data type. You won’t find a type description for it in documentation. Rather Any is an alias for any data type.

Similarly, AnyObject is an alias for any data type derived from a class. You can use it to define an array that contains more than one object derived from a class, that don’t share a common root class:

class Test {}
class Test2 {}
//No error, test is defined as [AnyObject]
var test:[AnyObject] = [Test(),Test2()]

(You could of course have used [Any] as well – [AnyObject] is just a little more specific.

Passing in a string and an integer for example, to an AnyObject array will cause an error, as these data types are structs in Swift.

//Error: String does not conform to element type 'AnyObject'
var test:[AnyObject] = ["a",0]

Of course, an Array which could contain any data type is unlikely to pop up in your code, and if it does, maybe you should double-check you’re following best practices!
Rather, this has been an exercise to explore Any, AnyObject, NSObject, NSArray and how Swift 3 now requires explicit bridging between Foundation and native data types. Hopefully this helps!

Interactive developer, Author - iOS development with Swift - book coming 2017 https://manning.com/books/ios-development-with-swift

Tagged with: ,
Posted in Swift
2 comments on “Any vs AnyObject vs NSObject in Swift 3
  1. […] This post has been updated for Swift 3 here. […]

  2. Very clear explanation. I like that type of articles. Thank you!

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s

%d bloggers like this: