What is type casting in Swift? How to use is, as, as?, and as! for type casting?
Type casting in Swift is used to check the type of an instance, or to treat it as a superclass or subclass. Type casting is very important when dealing with polymorphism and inheritance hierarchies.
is Operator:
- Checks if an instance is an instance of a specific type
- Returns a boolean value
- Example:
swift
class Vehicle {} class Car: Vehicle {} class Truck: Vehicle {} let vehicle = Car() print(vehicle is Car) // true print(vehicle is Vehicle) // true print(vehicle is Truck) // false
as Operator:
- Used for upcasting (subclass to superclass)
- Always succeeds
- Example:
swift
let car = Car() let vehicle = car as Vehicle
as? Operator:
- Used for downcasting (superclass to subclass)
- Returns an optional type
- Returns nil when conversion fails
- Example:
swift
let vehicle: Vehicle = Car() if let car = vehicle as? Car { print("This is a car") } if let truck = vehicle as? Truck { print("This is a truck") } else { print("Not a truck") }
as! Operator:
- Used for forced downcasting
- Triggers runtime error when conversion fails
- Only use when you're certain the conversion will succeed
- Example:
swift
let vehicle: Vehicle = Car() let car = vehicle as! Car // Dangerous: may cause crash // let truck = vehicle as! Truck
Practical Applications of Type Casting:
swiftclass MediaItem { var name: String init(name: String) { self.name = name } } class Movie: MediaItem { var director: String init(name: String, director: String) { self.director = director super.init(name: name) } } class Song: MediaItem { var artist: String init(name: String, artist: String) { self.artist = artist super.init(name: name) } } let library = [ Movie(name: "Casablanca", director: "Michael Curtiz"), Song(name: "Blue Suede Shoes", artist: "Elvis Presley"), Movie(name: "Citizen Kane", director: "Orson Welles"), Song(name: "The One And Only", artist: "Chesney Hawkes"), Song(name: "Never Gonna Give You Up", artist: "Rick Astley") ] var movieCount = 0 var songCount = 0 for item in library { if item is Movie { movieCount += 1 } else if item is Song { songCount += 1 } } print("Media library contains \(movieCount) movies and \(songCount) songs") for item in library { if let movie = item as? Movie { print("Movie: \(movie.name), dir. \(movie.director)") } else if let song = item as? Song { print("Song: \(song.name), by \(song.artist)") } }
Any and AnyObject Type Casting:
swiftvar things = [Any]() things.append(0) things.append(0.0) things.append(42) things.append(3.14159) things.append("hello") things.append((3.0, 5.0)) things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman")) for thing in things { switch thing { case 0 as Int: print("zero as an Int") case 0 as Double: print("zero as a Double") case let someInt as Int: print("an integer value of \(someInt)") case let someDouble as Double where someDouble > 0: print("a positive double value of \(someDouble)") case is Double: print("some other double value that I don't want to print") case let someString as String: print("a string value of \"\(someString)\"") case let (x, y) as (Double, Double): print("an (x, y) point at \(x), \(y)") case let movie as Movie: print("a movie called \(movie.name)") default: print("something else") } }
Best Practices:
- Use is to check types
- Use as? for safe type casting
- Only use as! when you're certain the conversion will succeed
- Use switch to handle multiple types
- Avoid overusing Any and AnyObject