Difference between Any vs AnyObject in Swift
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.
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:
1
2
| //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?
1
2
3
| 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.
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?
1
2
3
| 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.
1
2
| //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.
1
2
3
| 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:
1
2
3
4
| 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.
1
2
| //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
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
No comments:
Post a Comment
Please comment here...