The concept of Any
and AnyObject
is a compromise in Swift, and confuses developers. In the "Swift Programming Language "from Apple, it is described as:
AnyObject
can represent an instance of any class type.
Any
can represent an instance of any type, even including the function type.
Check and see AnyObject
first. Objective-C developers are well aware of type id
. The compiler will not check the actual type of id
, so it can express the concept of any type of object. Cocoa framework uses quite a lot of id
in parameters and return values. Right now, Swift is primarily used in app development with Cocoa. Since we need to use APIs from Cocoa, AnyObject
is a replacement for id
, which means an instance of a class
type.
But there is a conspicuous gap between id
and AnyObject
. Swift compiler will not check whether method exists or not when called on an AnyObject
. And all return of AnyObject
instance would be an Optional value. This makes sense in Objective-C, but a little troublesome in Swift. When using an object in Swift, we should always do a type casting before using an AnyObject
.
Say that we have an API returning id
in Objective-C, it now returns AnyObject?
(because id
could be a nil
as well, so we need an Optional value here). Although we know calling a specified method on it SHOULD be no problem, we often cast it first instead:
func someMethod() -> AnyObject? {
// ...
// result is an `AnyObject?` value, which is equivalent to `id`.
return result
}
let anyObject: AnyObject? = SomeClass.someMethod()
if let someInstance = anyObject as? SomeRealClass {
// ...
// Now, `someInstance` is `SomeRealClass` type. Use it directly.
someInstance.funcOfSomeRealClass()
}
In fact, AnyObject
is an empty protocol under the hood:
protocol AnyObject {
}
Distinct from other protocols, all class
types conform to this protocol implicitly. This is why AnyObject
can only represent class
type. In Swift, Array
and Dictionary
are struct
, instead of the class type in many other languages. The struct
cannot be described into AnyObject
, and this is why Any
comes in. Besides of class
, Any
can be utilized in all other types too, including struct
and enum
.
To help understand it better, we can have a test on Any
and AnyObject
. Write this in an iOS's playground. Please take notice of the first line:
import UIKit
let swiftInt: Int = 1
let swiftString: String = "miao"
var array: [AnyObject] = []
array.append(swiftInt)
array.append(swiftString)
(You can also do the same thing in a Mac playground, in which the first line would be import AppKit
instead.)
import UIKit
means we like to take Cocoa in this file. We declared an Int
and a String
here, which are both struct
and can only be represented by Any
, but not by AnyObject
. But surprisingly, the code gets compiled and can run correctly. However, if we print out the elements in array
, we can find the types of these elements are changed to NSNumber
and NSString
, which are not original Swift types as declared. Yes, the secret is import UIKit
. When importing UIKit
, you imported Foundation
as well, in which NSNumber
and NSString
are also included. These types and Swift corresponding types can be converted seamless. Here we declared AnyObject
is the type that should be stored in the array. So Int
and String
are converted automatically to their "variant" in Cocoa.
If we remove the import UIKit
line, we will have an error saying types are not correct as expected. And if we change the array from [AnyObject]
to [Any]
, everything will work again, and the types are exactly the ones we declared:
let swiftInt: Int = 1
let swiftString: String = "miao"
var array: [Any] = []
array.append(swiftInt)
array.append(swiftString)
array
Using Swift original types without converting to Cocoa types benefits the performance. And it will be a wise choice to use Swift types as often as possible when writing your code in Swift.
It can hardly make you happy if you insist on using a lot of Any
or AnyObject
. As stated in the beginning of this article, it is just a compromise in Swift. If Any
or AnyObject
exists in your code here and there, it might mean a bad smell in your code. Try to avoid depending and using them in your code, you will be benefited from pointing out the real type of your objects at the time.