Swift, as I am sure you are aware, is quite a strict, safe and strongly-typed language. However, because the language needs to maintain Objective-C compatibility it has some rather curious features, and the behaviour of AnyObject
is one of them!
AnyObject and relaxed type-safety
AnyObject
is a protocol that can represent an instance of any class type. It also has a more general counterpart, Any
, which can represent any type at all (including structs and enums).
As you might expect, the following code will not compile:
It fails with the error ‘AnyObject’ does not have a member named ‘saySomething()’.
When provided with an instance of AnyObject you have to cast to the required type in order to execute its methods or access properties:
This all makes sense so far, but here is where things get a little curious. If you import Foundation and mark the class with the @objc
attribute, you no longer have to cast from AnyObject
to Cat
in order to invoke the saySomething
method:
This is pretty odd behaviour! And as you can imagine, it is also unsafe. It is quite possible to write code that compiles, yet fails at runtime:
Whilst this behaviour is understandable to people who came to Swift via Objective-C, I can guarantee it will confuse people who are new to iOS development!
AnyObject and sneaky type conversions
If you try to create a ‘mixed’ array containing strings and numbers you will encounter difficulties:
AnyObject
can represent any class instance, but Swift’s string and numeric types are all structs (i.e. value types).
However, as soon as you import Foundation, the compiler errors go away:
How on earth does that work? From inspecting the contents of the array you can see that the compiler has automatically converted those literal values into a NSString
and NSSNumber
:
Conclusions
Take care when using AnyObject
, you can do some pretty strange things with that types. In fact, take care when using Swift with Objective-C at all! ;-)
Regards, Colin E.