Type Casting in Swift

In object-oriented programming, type casting is used to treat an object as one of another type. In this article we will discuss how this works in Swift.

Car and Vehicle

Let’s start by defining the test classes car and vehicle:

class Vehicle {
    
}

class Car: Vehicle {
    
}

Now we can declare some objects:

let car: Car = Car()
let vehicle: Vehicle = Vehicle()
let anotherVehicle: Vehicle = Car()

The interesting one here is anotherVehicle: Its type is Vehicle, but it is actually a Car object. This is possible because every car is also a Vehicle. This is an example of polymorphism.

Upcasting

You are always allowed to assign an object to a variable, which has a type that is higher in the class hierarchy. The upcast is done implicitly. In our example, Vehicle is the superclass of Car, so the following assignment is perfectly fine:

vehicle = car

But it is also possible to do an explicit cast by using the keyword as:

vehicle = car as Vehicle

You can always do an upcast, if you can build an “is-a sentence”. In our example, car is a Vehicle. The same holds true with protocols. If the class of an object implements a protocol, the object can always be assigned to an variable that has the protocol type.

You can also check the “is-a sentence” programmatically by using the keyword is, which returns a boolean. Since car is a Car, you have the output “true”:

print(car is Car) //true

Furthermore, a car is also Vehicle:

print(car is Vehicle) //true

Downcasting

If you want to cast down the class hierarchy, it is little bit more difficult. So anotherVehicle has the type Vehicle, but the object is a Car. So we have:

print(anotherVehicle is Car) //true

It is perfectly fine to assign anotherVehicle to a variable of the Car type. But we are not allowed to do this without any additional twists:

car = anotherVehicle //Compiler Error

We have to do an explicit cast. But just an as is also not enough. We have to use as! or as?. The first can be used, if you are very sure that the cast is possible:

if anotherVehicle is Car {
    car = anotherVehicle as! Car
}

There would be an error at execution time, if the cast with as! failed.

The operator as? only performs the cast, if the cast is possible. Otherwise, it returns nil. So it is very suited to use it with optional binding:

if let anotherVehicle = anotherVehicle as? Car {
    car = anotherVehicle
}

References

Image: @ zmkstudio / shutterstock.com

3 comments

  1. I’ve been struggling to understand when I’d want to use the unqualified version of “as”. Since I can always implicitly upcast, I don’t see why I would ever need to do this:

    vehicle = car as Vehicle

    In Swift 1.0, I could use an unqualified “as” to do a downcast. However, Swift 1.2 changed this so it is now necessary to use either “!” or “?” to downcast. This is fine, but it seems to make the unqualified version unnecessary. Or am I missing something?

    1. You are right, in most cases you don’t need it.
      However, in the following example it makes a difference:

      let vehicle = car => “vehicle” has type “Car”
      let vehicle = car as Vehicle => “vehicle” has type “Vehicle”

      Though it has the same effect as using explicit type annotation:

      let vehicle: Car = car
      let vehicle: Vehicle = car

      Thanks for the question!

Comments are closed.