Type Casting
Version: Swift 5.6 Source: swift-book: Type Casting Digest Date: February 28, 2022
Overview
Type casting is a way to check the type of an instance, or to treat that instance as a different superclass or subclass from somewhere else in its own class hierarchy.
Type casting in Swift is implemented with the is and as operators. These two operators provide a simple and expressive way to check the type of a value or cast a value to a different type.
You can also use type casting to check whether a type conforms to a protocol, as described in Checking for Protocol Conformance.
Defining a Class Hierarchy for Type Casting
You can use type casting with a hierarchy of classes and subclasses to check the type of a particular class instance and to cast that instance to another class within the same hierarchy.
The three code snippets below define a hierarchy of classes and an array containing instances of those classes, for use in an example of type casting.
The first snippet defines a new base class called MediaItem. This class provides basic functionality for any kind of item that appears in a digital media library. Specifically, it declares a name property of type String, and an init name initializer. (It’s assumed that all media items, including all movies and songs, will have a name.)
The next snippet defines two subclasses of MediaItem.
The first subclass,
Movie, encapsulates additional information about a movie or film. It adds adirectorproperty on top of the baseMediaItemclass, with a corresponding initializer.The second subclass,
Song, adds anartistproperty and initializer on top of the base class:
The final snippet creates a constant array called library, which contains two Movie instances and three Song instances. The type of the library array is inferred by initializing it with the contents of an array literal. Swift’s type checker is able to deduce that Movie and Song have a common superclass of MediaItem, and so it infers a type of [MediaItem] for the library array:
The items stored in library are still Movie and Song instances behind the scenes.
However, if you iterate over the contents of this array, the items you receive back are typed as MediaItem, and not as Movie or Song. In order to work with them as their native type, you need to check their type, or downcast them to a different type, as described below.
Checking Type
Use the type check operator (is) to check whether an instance is of a certain subclass type. The type check operator returns true if the instance is of that subclass type and false if it’s not.
The example below defines two variables, movieCount and songCount, which count the number of Movie and Song instances in the library array:
Downcasting
A constant or variable of a certain class type may actually refer to an instance of a subclass behind the scenes. Where you believe this is the case, you can try to downcast to the subclass type with a type cast operator (as? or as!).
Because downcasting can fail, the type cast operator comes in two different forms:
The conditional form,
as?, returns an optional value of the type you are trying to downcast to.The forced form,
as!, attempts the downcast and force-unwraps the result as a single compound action.
Use the conditional form of the type cast operator (as?) when you aren’t sure if the downcast will succeed. This form of the operator will always return an optional value, and the value will be nil if the downcast was not possible. This enables you to check for a successful downcast.
Use the forced form of the type cast operator (as!) only when you are sure that the downcast will always succeed. This form of the operator will trigger a runtime error if you try to downcast to an incorrect class type.
The example below iterates over each MediaItem in library, and prints an appropriate description for each item. To do this, it needs to access each item as a true Movie or Song, and not just as a MediaItem. This is necessary in order for it to be able to access the director or artist property of a Movie or Song for use in the description.
Type Casting for Any and AnyObject
Swift provides two special types for working with nonspecific types:
Anycan represent an instance of any type at all, including function types.AnyObjectcan represent an instance of any class type.
Use Any and AnyObject only when you explicitly need the behavior and capabilities they provide. It’s always better to be specific about the types you expect to work with in your code.
Here’s an example of using Any to work with a mix of different types, including function types and nonclass types.
The example creates an array called things, which can store values of type Any:
The things array contains two Int values, two Double values, a String value, a tuple of type (Double, Double), the movie “Ghostbusters”, and a closure expression that takes a String value and returns another String value.
To discover the specific type of a constant or variable that’s known only to be of type Any or AnyObject, you can use an is or as pattern in a switch statement’s cases.
The example below iterates over the items in the things array and queries the type of each item with a switch statement. Several of the switch statement’s cases bind their matched value to a constant of the specified type to enable its value to be printed:
NOTE:
The Any type represents values of any type, including optional types. Swift gives you a warning if you use an optional value where a value of type Any is expected.
If you really do need to use an optional value as an Any value, you can use the as operator to explicitly cast the optional to Any, as shown below.
Last updated