Type Casting, Nested Types and Extensions
18.1 Type Casting
class MediaItem { let name: String; init(name: String) { self.name = name } }
class Movie: MediaItem { let director = "Unknown" }
class Song: MediaItem { let artist = "Unknown" }
let library: [MediaItem] = [Movie(name: "Inception"), Song(name: "Imagine")]
for item in library {
if let movie = item as? Movie { // conditional downcast
print("Movie by \(movie.director)")
} else if item is Song { // type check
print("Song")
}
}
let forced = library[0] as! Movie // forced downcast (crashes if wrong)
var things: [Any] = [0, 3.14, "hello", (1, 2), { (s: String) in s }]
for thing in things {
switch thing {
case let i as Int: print("Int \(i)")
case let s as String: print("String \(s)")
case let (x, y) as (Int, Int): print("tuple \(x), \(y)")
default: print("other")
}
}
let anyObject: AnyObject = Movie(name: "X") // any class instance18.2 Nested Types
struct BlackjackCard {
enum Suit: Character { case spades = "♠", hearts = "♡" }
enum Rank: Int {
case two = 2, three, ace = 14
struct Values { let first: Int, second: Int? }
var values: Values { self == .ace ? Values(first: 1, second: 11) : Values(first: rawValue, second: nil) }
}
let rank: Rank, suit: Suit
}
let heartsSymbol = BlackjackCard.Suit.hearts.rawValue18.3 Extensions
Extensions can add computed properties, methods, initializers, subscripts, nested types, and protocol conformances, but not stored properties or overrides of existing functionality.
extension Double {
var km: Double { self * 1_000 }
var m: Double { self }
}
let marathon = 42.195.km
extension Int {
func repetitions(_ task: () -> Void) { for _ in 0..<self { task() } }
mutating func square() { self = self * self }
subscript(digitIndex: Int) -> Int {
var base = 1
for _ in 0..<digitIndex { base *= 10 }
return (self / base) % 10
}
}
3.repetitions { print("Hi") }
746381295[0] // 5
extension Point: CustomStringConvertible { // add protocol conformance
var description: String { "(\(x), \(y))" }
}
extension Rectangle {
init(square side: Double) { self.init(width: side, height: side) } // keeps the memberwise init
}