타입캐스팅이란 인스턴스의 타입을 알아보거나 해당 타입의 수퍼클래스 혹은 서브클래스로 변환하는 작업을 의미하는데 크게 2가지 오퍼레이터를 사용한다.
Music 이라는 클래스를 상속받는 두개의 Classic, Hiphop 클래스를 가정해보자.
class Music {
var title: String
init(title: String) {
self.title = title
}
}
class Classic: Music {
var composer: String
init(title: String, composer: String) {
self.composer = composer
super.init(title: title)
}
}
class Hiphop: Music {
var rapper: String
init(title: String, rapper: String) {
self.rapper = rapper
super.init(title: title)
}
}
각 인스턴스를 상수에 할당한다.
let classic = Classic(title: "Canon", composer: "Pachelbel")
let hiphop = Hiphop(title: "Lose Yourself", rapper: "Eminem")
is 키워드를 사용하면 인스턴스의 타입을 체크해 볼 수 있다.
classic 은 Music 을 상속받는 Classic 의 인스턴스이므로 Classic 타입이면서 Music 타입이므로 타입체크를 해보면 다음과 같다.
classic is Classic // true
classic is Music // true
classic is Hiphop // false
이번엔 타입을 변환하는 타입캐스팅도 크게보면 수퍼클래스로 변환하는 업캐스팅과 서브클래스로 변환하는 다운캐스팅으로 나눠 볼 수 있는데 업캐스팅은 항상 성공할 수 밖에 없으므로 as 를 다음과 같이 사용하면 간단하게 변환된다.
let test = classic as Music
test 는 Music 타입이므로 composer 프로퍼티에 접근할 수 없다. 업캐스팅은 별로 효용성이 없으므로 거의 사용하지 않아서 보통 타입캐스팅이라하면 서브클래스로 변환하는 다운캐스팅을 의미한다.
다운캐스팅은 성공가능성에 따라 타입캐스트 오퍼레이터를 2가지 형식으로 사용한다.
classic 과 hiphop 을 담은 playList 배열을 만들어 보자.
let playList = [classic, hiphop]
각 엘리먼트를 접근해보면 Music 타입이므로 이때 다운캐스팅이 필요하다.
let first = playList[0] as? Classic // Classic?
let second = playList[1] as? Classic // nil
다음처럼 강제캐스팅을 시도할 경우 second 에서 에러가 발생한다.
let first = playList[0] as! Classic // Classic
let second = playList[1] as! Classic // error
그러므로 옵셔널캐스팅과 옵셔널 바인딩을 조합하여 다음처럼 사용하는 것이 안전하다.
for item in playList {
if let classic = item as? Classic {
print("Classic: \(classic.title), made \(classic.composer)")
} else if let hiphop = item as? Hiphop {
print("Hiphop: \(hiphop.title), by \(hiphop.rapper)")
}
}
Classic: Canon, made Pachelbel
Hiphop: Lose Yourself, by Eminem