Type casting in Swift is implemented with is
and as
operators.
Type casting:
- A subclass instance can be use as a superclass instance.
Defining a Class Hierarchy
class Media {
var name: String
init(name: String) {
self.name = name
}
}
class Song: Media {
var artist: String
init(name: String, artist: String) {
self.artist = artist
super.init(name: name)
}
}
class Movie: Media {
var director: String
init(name: String, director: String) {
self.director = director
super.init(name: name)
}
}
var library = [
Movie(name: "A", director: "Michael"),
Song(name: "B", artist: "Elvis"),
Movie(name: "C", director: "Orson"),
Song(name: "D", artist: "Rick"),
Media(name: "E")
]
// The "library" is inferred to be [Media]
for item in library {
print(item.name) // Here the item is of "Media" type
}
// If we want to use the library's item as the subclass instance, we should downcast the item.
Checking Type
Use is
to check whether an instance is of a certain subclass type.
for item in library {
if item is Movie {
print(item.name + " is Movie")
} else if item is Song {
print(item.name + " is Song")
} else {
print(item.name + " is Media")
}
}
When set the movies and songs to the library
, it’s the automatically upcast. The upcast is a type of polymorphism.
Downcasting
When we believe that a superclass instance is actually of a subclass type, we can downcast the instance to be a subclass type.
Two way to downcast a instance:
as?
get an optional result. (Recommended)as!
force downcast, it will trigger runtime error when the types not match.
for item in library {
if let movie = item as? Movie {
print(movie.name + " " + movie.director)
} else if let song = item as? Song {
print(song.name + " " + song.artist)
}
}
// Print:
// A Michael
// B Elvis
// C Orson
// D Rick
// E is just a Media
Type Casting for Any and AnyObject
Any
can represent an instance of any type at all, including function type, including class type.AnyObjece
can represent an instance of any class type.
var things: [Any] = []
things.append(0)
var a: Int? = 3
things.append(a as Any)
things.append(4.0)
things.append(42)
things.append("Oh")
things.append((2.0, 3.5))
things.append(Media(name: "LoL"))
things.append({(name: String) -> String in "Hello, \(name)"})
for thing in things {
switch thing {
case is Int:
print("\(thing) is Int")
case let someDouble as Double where someDouble > 2:
print("Double \(someDouble) is greater than 2")
case is Double:
print("\(thing) is Double")
case let s as String:
print("\(thing) is String")
case let (x, y) as (Double, Double):
print("x: \(x) y: \(y)")
case let media as Media:
print("Media: \(media.name)")
case let say as (String) -> String:
print("Func: \(say("John"))")
default: break
}
}
// Print:
// 0 is Int
// Optional(3) is Int
// Double 4.0 is greater than 2
// 42 is Int
// Oh is String
// x: 2.0 y: 3.5
// Media: LoL
// Func: Hello, John
If we want to use an optional variable as Any
, write as Any
, otherwise
Swift will give us a warning.
var a: Int? = 3
things.append(a) // Warning
things.append(a as Any) // No warning