Skip to main content

Type Casting

타입 캐스팅 정의

Swift 코드를 작성할 때 컴파일러가 어떤 값의 특정 타입을 식별하지 못하는 경우가 발생합니다. 이런 경우 메서드나 함수가 반환하는 값이 불명확하거나 예상되지 않은 타입의 값일 때 종종 발생하게 됩니다. 이럴 때는 as 키워드를 사용하여 여러분의 코드가 의도하는 값의 타입을 컴파일러가 알 수 있게 해야 합니다. 이를 저희는 타입 캐스팅 이라고 부르기로 했습니다.

쉽게 생각해서 타입 캐스팅은 인스턴스의 타입을 확인하거나, 해당 인스턴스를 슈퍼 클래스나 하위 클래스로 취급하는 방법입니다.

업캐스팅과 다운캐스팅

예를 들어, 다음은 object(forKey:) 메서드가 반환하는 값을 String 타입으로 처리해야 한다고 컴파일러에게 알려주는 코드입니다.

let myValue = record.object(for: "comment") as! String

실제로 타입 캐스팅에는 업캐스팅과 다운캐스팅이라는 두 가지 형태가 있다. 업캐스팅은 특정 클래스의 객체가 상위 클래스들 중의 하나로 변형되는 것을 말한다. 업캐스팅은 as 키워드를 사용하여 수행되며, 이러한 변환은 성공할 것이라고 컴파일러가 알려줄 수 있기 때문에 보장된 변환이라고 합니다. 이를 서브 클래스 인스턴스를 “슈퍼 클래스의 타입”으로 참조하며 보장된 변환을 하기 때문에 업 캐스팅은 항상 성공합니다.

업캐스팅

예를 들어서, 아래 그림과 같이 UIKit 클래스 계층 구조를 볼 때 UISlider 클래스는 UIControl 클래스의 하위 클래스입니다.

UISliderUIControl의 하위 클래스이므로 다음과 같이 안전하게 업캐스팅될 수 있습니다.

let testSlider = UISlider()
let testControl = testSlider as UIControl

반면, 다운 캐스팅은 어떤 클래스에서 다른 클래스로 만드는 변환이 일어날 때 발생합니다. 이런 변환이 안전하게 수행된다거나 유효하지 않은 변환 시도를 컴파일러가 잡아낼 것이라는 보장을 할 수 없습니다. 다운 캐스팅으르로 유효하지 않은 변환을 했는데 컴파일러가 발견하지 못한다면, 대부분의 경우 런타임 에러가 발생하게 됩니다.

다운캐스팅

다운캐스팅은 보통 어떤 클래스에서 그 클래스의 하위 클래스로 변환하게 됩니다. 이를 슈퍼 클래스 인스턴스를 “서브 클래스의 타입”으로 참조한다고 합니다. 다운캐스팅은 as! 키워드로 수행됩니다. 이를 강제 변환이라고 부릅니다.

as!는 런타임 시점에 타입 캐스팅(다운 캐스팅)을 하며, 실패할 경우 에러를 발생시킵니다. 때문에 특수한 상황이 아니라면 as?를 사용하는 것을 추천드립니다.

위 그림에서 만약 UIViewUIControl이 되려고 한다면 그것을 강제 변환이라고 하게 됩니다. 이럴 경우 UIView 객체를 UIControl 클래스로 변환하기 위해서는 다운캐스팅이 필요합니다. 아래는 코드는 UIViewUIControl로 다운 캐스팅하는 코드입니다.

let testView = UIView()
let testControl = testView as UIControl

위와 같이 코드를 작동시키면 아래 에러가 날 것입니다:

'UIView' is not convertible to 'UIControl'

컴파일러는 UIView 인스턴스를 UIControl 클래스 인스턴스로 안전하게 변환할 수 없음을 알려줍니다. 이것은 이렇게 하는 것이 틀렸다는 것을 의미하는 것이 아니라 컴파일러는 지금 이것은 안전한 선택이 아니다를 말하고 있습니다. 저희가 이 선택이 맞다고 생각하시면 as 뒤에 ! 를 붙여서 강제적으로 다운캐스팅을 진행시킬 수 있습니다.

let testControl = testView as! UIControl

이제 컴파일 오류는 없어졌을 것입니다. 하지만, UIViewUIControl로 변환할 수 없어서 에러가 날 것 입니다. 때문에 여러분이 강제 다운 캐스팅을 사용하는 것은 주의가 많이 필요합니다.

지금까지 보아왔듯이 다운 캐스팅은 업캐스팅과 달리 실패할 수 있습니다.

다운캐스팅을 하는 더 안전한 방법은 as?를 사용한 옵셔널 바인딩을 하는 것입니다.

as? 는 런타임 시점에 타입 캐스팅(다운 캐스팅)을 하며, 실패할 경우 nil을 리턴합니다. 만약에 성공적으로 수행된다면 지정한 타입의 옵셔널을 반환하게 됩니다. 때문에 as?를 사용하기 위해서는 Optional-Type으로 선언해주어야합니다.

if let testControl = testView as? UIControl {
print("변환 성공")
} else {
print("변환 실패")
}

is 키워드

is 키워드를 사용하여 타입 검사를 할 수도 있습니다. is 클래스의 표현식은 아래와 같습니다:

표현식 is Type

타입을 체크하는 연산자로, 런타임 시점에 실제 체크가 이루어지게 됩니다. 표션식이 Type과 동일하거나, 표현식이 Type의 서브 클래스인 경우 true이며 아니면 flase를 내뱉습니다. 그러면 저희가 알 수 있는 것은 is 연산자는 반환 값이 Bool형이라는 것입니다.

예를 들어, 다음은 해당 객체가 TestClass라는 이름의 클래스의 인스턴스인지를 검사하는 코드입니다.

if myobject is TestClass {
// myobject는 TestClass의 인스턴스다.
}