🔥 다운캐스팅

488자
7분

특정 클래스 타입의 상수나 변수가 실제로는 서브클래스의 인스턴스를 참조하고 있을 수 있어요. 이런 경우라고 생각되면, as? 또는 as! 연산자를 사용하여 서브클래스 타입으로 다운캐스트를 시도해볼 수 있지요.

다운캐스팅은 실패할 수 있기 때문에, 타입 캐스트 연산자에는 두 가지 다른 형식이 있어요. 조건부 형식인 as?는 다운캐스트하려는 타입의 옵셔널 값을 반환하고, 강제 형식인 as!는 다운캐스트를 시도하고 결과를 단일 복합 동작으로 강제 언래핑합니다.

다운캐스트가 성공할지 확신할 수 없을 때는 타입 캐스트 연산자의 조건부 형식(as?)을 사용하세요. 이 형식의 연산자는 항상 옵셔널 값을 반환할 거예요. 만약 다운캐스트가 불가능하다면 이 값은 nil이 될 거랍니다. 이를 통해 다운캐스트의 성공 여부를 확인할 수 있지요.

다운캐스트가 항상 성공할 거라고 확신할 때만 타입 캐스트 연산자의 강제 형식(as!)을 사용하세요. 잘못된 클래스 타입으로 다운캐스트를 시도하면 이 형식의 연산자는 런타임 오류를 발생시킬 거예요.

아래 예제는 library의 각 MediaItem을 순회하면서, 각 항목에 대한 적절한 설명을 출력해요. 이를 위해서는 각 항목을 진짜 MovieSong으로 접근해야 하고, 단순히 MediaItem으로 접근해서는 안 됩니다. 설명에 사용하기 위해 Moviedirector 속성이나 Songartist 속성에 접근하려면 이것이 필요하지요.

이 예제에서 배열의 각 항목은 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
swift

이 예제는 먼저 현재 itemMovie로 다운캐스트하려고 시도해요. itemMediaItem 인스턴스이기 때문에 Movie일 가능성이 있어요. 마찬가지로 Song일 수도 있고, 심지어 그냥 기본 MediaItem일 수도 있지요. 이런 불확실성 때문에, 서브클래스 타입으로 다운캐스트를 시도할 때 as? 형식의 타입 캐스트 연산자는 옵셔널 값을 반환합니다. item as? Movie의 결과는 Movie?, 즉 "옵셔널 Movie" 타입이에요.

라이브러리 배열의 Song 인스턴스에 적용되면 Movie로의 다운캐스팅은 실패해요. 이를 처리하기 위해, 위의 예제는 옵셔널 바인딩을 사용하여 옵셔널 Movie에 실제로 값이 포함되어 있는지(즉, 다운캐스트가 성공했는지) 확인하고 있어요. 이 옵셔널 바인딩은 "if let movie = item as? Movie"로 작성되는데, 이는 다음과 같이 읽을 수 있지요:

"itemMovie로 접근하려고 시도해봐. 만약 이것이 성공하면, 반환된 옵셔널 Movie에 저장된 값을 movie라는 새로운 임시 상수에 설정해."

만약 다운캐스팅이 성공하면, movie의 속성들이 해당 Movie 인스턴스에 대한 설명을 출력하는 데 사용되는데, 여기에는 director의 이름도 포함돼요. Song 인스턴스를 확인하고 라이브러리에서 Song이 발견될 때마다 적절한 설명(artist 이름 포함)을 출력하는 데에도 유사한 원리가 사용됩니다.

이처럼 다운캐스팅은 런타임에 인스턴스의 실제 타입을 확인하고 해당 타입에 맞는 속성과 메서드에 접근하는 데 매우 유용해요. 하지만 항상 옵셔널 바인딩을 사용하여 다운캐스팅의 성공 여부를 확인해야 한다는 점을 기억하세요. 그렇지 않으면 런타임 오류가 발생할 수 있답니다!

아래는 다운캐스팅이 어떻게 작동하는지 보여주는 플로우차트예요.

lecture image

이 플로우차트는 MediaItem 인스턴스에서 시작해서, 먼저 Movie로의 다운캐스트를 시도해요. 만약 성공하면 Movie 속성에 접근할 수 있지요. 실패하면 Song으로의 다운캐스트를 시도하고, 성공 시 Song 속성에 접근합니다. 두 다운캐스트 모두 실패하면 다운캐스팅이 실패한 것으로 간주되지요.