programming, user experience, and more


Swift’s Weird Handling of Basic Value Types and AnyObject

I recently wrapped my head around something that I have found very strange in Swift. Swift provides two high level protocols called Any and AnyObject. Any can be used for both value types (like structs) and reference types (classes) while AnyObject can only be used for classes.

As expected this code produces a compilation error:

var objects : [AnyObject] = []
var aString : String = "Hello"
objects.append(aString) // The type ‘String’ does not conform to protocol ‘AnyObject’

However, by simply adding import Foundation to the top, it compiles and runs fine:

import Foundation

var objects : [AnyObject] = []
var aString : String = "Hello"
objects.append(aString)

What is going on here?

The reason this works fine, is because the compiler is actually converting aString to NSString implicitly. String is a struct but NSString is a class. If Foundation is not imported, this conversion is not possible because it doesn’t know about NSString.

This also happens with numbers like Int which can be implicitly converted to the class type NSNumber.

This means that in Swift, strings and numbers can be treated as both value types and reference types.

This seems to go against Swift's policy of always requiring explicit conversions between types, but I guess it is a compromise to allow working with Objective-C much easier.

Be careful of this “magic” conversion. You may be using a reference type when you are expecting it to be a value type. I recommend removing import Foundation whenever possible.