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은 인스턴스의 유형을 확인하거나 해당 인스턴스를 다른 수퍼 클래스 또는 하위 클래스로 취급하는 방법입니다
import Foundation
class 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)
}
}
is
연산자를 이용해 특정 인스턴스의 타입을 확인할 수 있습니다.
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")
// Media library contains 2 movies and 3 songs
여기서 library
는 MediaItem
의 인스턴스가 담겨있다고 말해준다. type Inference으로 당연한거지만 타입캐스팅을 다룰 때면 이상하게 인지하고 있지 못했다.
as는 해당 타입이 캐스팅이 되는지 바로 알려줍니다. 여기서 as의 실행 시점을 확인할 수 있습니다.
let fly = Movie(name: "Fly!", director: "Ji")
print((fly as MediaItem).name) // Fly!
print((fly as Movie).name) // // Fly!
//print((fly as Song).name) // Cannot convert value of type 'Movie' to type 'Song' in coercion
그러면 아까 library와 같이 (형 확인의 is
의 방법도 있지만) 배열이나 해시테이블 등 특정할 수 없다면 어떻게 할까? as?
와 as!
를 활용하면 됩니다.
as?
와 as!
연산자를 이용해 어떤 타입의 인스턴스인지 확인할 수 있습니다. as?
는 특정 타입이 맞는지 확신할 수 없을때 사용하고 as!
는 특정 타입이라는 것이 확실한 경우에 사용합니다. 다음 예제는 library
배열의 mediaItem
이 Movie
인스턴스 일수도 있고 Song
인스턴스일 수도 있기 때문에 다운캐스팅을 위해 as?
연산자를 사용했습니다.
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)")
}
}
//Movie: Casablanca, dir. Michael Curtiz
//Song: Blue Suede Shoes, by Elvis Presley
//Movie: Citizen Kane, dir. Orson Welles
//Song: The One And Only, by Chesney Hawkes
//Song: Never Gonna Give You Up, by Rick Astley
정상적으로 캐스팅이 잘 되는걸 확인할 수 있습니다. if let
을 사용한 것처럼 옵셔널로 반환이 됩니다
print(library[0] as? Movie)
//Optional(TestAndTest.Movie)
as!
으로 다운캐스팅을 했는데 지정한 타입이 아니라면 런타임 에러가 발생합니다.
print(library[0] as! Song)
//런타임 에러!!
as는 컴파일타임에, as?와 as!는 런타임에 실행된다고 합니다.
reference
https://zeddios.tistory.com/265
https://gaki2745.github.io/swift/2019/10/02/Swift-Basic-04/
https://docs.swift.org/swift-book/LanguageGuide/TypeCasting.html