Downcasting using as! and as? in Swift
What is Downcasting ?
Behind the scenes a variable or constant of a class type may be a subclass of another class type.
For example a variable of type Any may be referring to a String.
Here is another example of class Pet
class Pet { var name: String init(name: String) { self.name = name } }
Then we define two subclasses of Pet
class Dog: Pet { var breed: String init(name: String, breed: String) { self.breed = breed super.init(name: name) } } class Cat: Pet { var color: String init(name: String, color: String) { self.color = color super.init(name: name) } }
Finally we will create an array that contains one dog and two cats
let pets = [Dog(name: "Thor", breed: "Bulldog"), Cat(name: "Sophia", color: "Yellow"), Cat(name: "Tigress", color: "Black")]
The Swift type checker knows that Dog and Cat classes have a common subclass of Pet so the Pets array is inferred to be [Pet]
If you iterate over the pets array the items you get back are of type Pet but behind the scenes they are still Dog and Cat types
To use them as Dog and Cat you need to Downcast them using as! or as?
Using as! and as? to downcast
as? is a conditional cast operator and it always returns an optional so if the downcast failed you will get nil
as! is a forced cast operator so if the downcasting failed you will get a runtime error, this is why you must be sure that the downcast will succeed if you decided to use as!
Back to our example lets use as? to cast the items of our pets array
for pet in pets { if let dog = pet as? Dog { print("a dog named \(dog.name) and breed \(dog.breed)") } else if let cat = pet as? Cat { print("a cat named \(cat.name) and color \(cat.color)") } }
this is the result
a dog named Thor and breed Bulldog a cat named Sandy and color Yellow a cat named Tigress and color Black
Note that we have used the conditional downcast operator as? because we are not sure which item is Dog and which one is Cat but if for example we are sure that all items are of Dog class type then we could use the forced downcast operator as!