In messing around with Swift today I came across a strange thing. Here's the unit test I developed which shows some unexpected behaviours when using Swift's AnyObject.
class SwiftLanguageTests: XCTestCase {
class TestClass {
var name:String?
var xyz:String?
}
func testAccessingPropertiesOfAnyObjectInstancesReturnsNils() {
let instance = TestClass()
instance.xyz = "xyz"
instance.name = "name"
let typeAnyObject = instance as AnyObject
// Correct: Won't compile because 'xyz' is an unknown property in any class.
XCTAssertEqual("xyz", typeAnyObject.xyz)
// Unexpected: Will compile because 'name' is a property of NSException
// Strange: But returns a nil when accessed.
XCTAssertEqual("name", typeAnyObject.name)
}
}
This code is a simplification of some other code where there is a Swift function that can only return a AnyObject
.
As expected, after creating an instance of TestClass
, casting it to AnyObject
and setting another variable, accessing the property xyz
won't compile because AnyObject
does not have such a property.
But surprisingly a property called name
is accepted by the compiler because there is a property by that name on NSException
. It appears that Swift is quite happy to accept any property name as long as it exists somewhere in the runtime.
The next unexpected behaviour and the thing that got all this started is that attempting to access the name
property returns a nil. Watching the various variables in the debugger, I can see that typeAnyObject
is pointing at the original TestClass
instance and it's name
property has a value of "name".
Swift doesn't throw an error when accessing typeAnyObject.name
so I would expect it to find and return "name". But instead I get nil.
I would be interested if anyone can shed some light on what is going on here?
My main concern is that I would expect Swift to either throw an error when accessing a property that does not exist on AnyObject
, or find and return the correct value. Currently neither is happening.