타입 캐스팅이란?
인스턴스의 타입을 확인하거나 인스턴스를 같은 계층에 있는 다른 상위 클래스나 하위 클래스로 취급하는 방법
is
, as
를 사용class MediaItem {
var name: String
init(name: String) {
self.name = name
}
}
// MediaItem 이라는 클래스를 서브 클래싱 해서 두 개의 다른 서브 클래스를 만든다
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)
}
}
// Movie와 Song 두 개의 클래스를 아이템으로 갖는 library 배열 선언
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")
]
// the type of "library" is inferred to be [MediaItem]
library
가 갖고 있는 Movie
, Song
인스턴스의 공통 부모는 MediaItem
이기 때문에 library
는 타입 추론에 의해 [MediaItem]
배열의 형을 갖게 된다.
타입 지정을 위해서는 downcasting
을 이용해야 한다.
is
연산자를 이용해 특정 인스턴스의 타입을 확인할 수 있다.
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" 출력
특정 클래스 타입의 상수나 변수는 특정 서브클래스의 인스턴스를 참조하고 있을 수 있다.
as?
, as!
연산자를 이용해 어떤 타입의 인스턴스인지 확인
as?
: 특정 타입이 맞는지 확신할 수 없을 때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
캐스팅은 실제 인스턴스나 값을 바꾸는 것이 아니라 지정한 타입으로 취급하는 것이다.
Swift에서는 비특정 타입 작업을 위해 2가지를 제공한다:
Any
는 함수 타입을 포함하여 모든 타입의 인스턴스를 나타낼 수 있다.AnyObject
모든 클래스 타입의 인스턴스를 나타낼 수 있다.Any
타입의 예제
things
라는 Any
타입 배열을 선언해 여러 타입의 값을 저장한다.
var 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"))
things.append({ (name: String) -> String in "Hello, \(name)" })
Any
또는 AnyObject
타입으로만 알려진 상수 또는 변수의 특정 타입을 알아보려면 switch
구문의 케이스로 is
또는 as
패턴을 사용할 수 있다.
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), dir. \(movie.director)")
case let stringConverter as (String) -> String:
print(stringConverter("Michael"))
default:
print("something else")
}
}
// zero as an Int
// zero as a Double
// an integer value of 42
// a positive double value of 3.14159
// a string value of "hello"
// an (x, y) point at 3.0, 5.0
// a movie called Ghostbusters, dir. Ivan Reitman
// Hello, Michael
Any
타입은 옵셔널 타입을 포함한다. 하지만 Swift에서는Any
타입을 사용해야 하는 곳에 옵셔널을 사용하면 경고를 발생시킨다.
Any
값으로 옵셔널 값을 사용해야 한다면as
연산자를 사용해 명시적으로 옵셔널을Any
로 캐스트할 수 있다.let optionalNumber: Int? = 3 things.append(optionalNumber) // Warning things.append(optionalNumber as Any) // No warning