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:
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!
[…] This post has been updated for Swift 3 here. […]
Very clear explanation. I like that type of articles. Thank you!
Any is not all objects. It encompasses valuetypes and referencetypes.
Hey Mark. I’m curious, what are you specifically excluding?
[…] Craig Grummitt: Any vs. AnyObjects […]
[…] For more info visit: https://craiggrummitt.com/2016/09/16/any-vs-anyobject-vs-nsobject-in-swift-3/ […]