타입캐스팅

피터·2022년 9월 1일
0
post-thumbnail

스위프트 타입캐스팅

다른 타입 변환 혹은 타입캐스팅을 이니셜라이저로 단순화합니다.

var stringValue = "123"
var intValue = Int(stringValue) // Optional(123)

스위프트의 타입캐스팅은 인스턴스의 타입을 확인하거나 자신을 다른 타입의 인스턴스인 것처럼 행세할 수 있는 방법으로 사용할 수 있습니다. 스위프트의 타입캐스팅은 is와 as 연산자로 구현했습니다.

is와 as 연산자로 값의 타입을 확인하거나 다른 타입으로 전환할 수 있고, 또 프로토콜을 준수하는지도 확인이 가능합니다.

class Coffee {
    let 원두: String
    let shot: Int
    
    var description: String {
        return "저희 커피 원두는 \(원두)이고 \(shot)샷이 들어갑니다."
    }
    
    init(shot: Int) {
        self.shot = shot
        self.원두 = "에티오피아"
    }
}

class Latte: Coffee {
    var: String
    
    override var description: String {
        return "저희 집 커피 원두는 \(원두)이고\n이 커피는 \() 라떼입니다.\(shot) 샷입니다."
    }
    
    init(: String) {
        self.=super.init(shot: 2)
    }

		func 만드는방법() -> String {
        return "잔에 \(shot)샷을 넣고 데운 우유 위에 \() 시럽을 뿌려주세요."
    }
}

class Americano: Coffee {
    let iced: Bool
    
    override var description: String {
        return "저희 집 커피 원두는 \(원두)이고\n이 커피는 \(iced ? "아이스": "핫") 아메리카노입니다."
    }
    
    init(iced: Bool) {
        self.iced = iced
        super.init(shot: 1)
    }
}

데이터 타입 확인(is)

let coffee = Coffee(shot: 3)
let latte = Latte(: "바닐라")
let americano = Americano(iced: true)

print(coffee is Coffee) // true 
print(coffee is Latte) // false
print(coffee is Americano) // false

print(latte is Coffee) // true
print(americano is Coffee) // true

print(americano is Latte) // false
print(latte is Americano) // false

is 연산자 외에대 타입을 확인해볼 수 있는 방법이 있습니다. 메타 타입(Meta Type) 타입을 이용하는 것입니다.

메타 타입 타입은 타입의 타입을 뜻합니다. 클래스 타입, 구조체 타입, 열거형 타입, 프로토콜 타입 등의 타입의 타입입니다. 즉, 타입 자체가 하나의 타입으로 또 표현할 수 있다는 것입니다.

클래스, 구조체, 열거형의 이름은 타입의 이름입니다. 그 타입의 이름 뒤에 .Type을 붙이면 이는 메타 타입을 나타냅니다. 프로토콜 타입의 메타 타입은 .Protocol이라고 붙여주면 됩니다.

또, self를 사용해서 타입을 값처럼 표현할 수 있습니다. 예를 들어 SomeClass.self라고 표현하면 SomeClass의 인스턴스가 아니라 SomeClass 타입을 값으로 표현한 값을 반환합니다.

protocol SomeProtocol { }
class SomeClass: SomeProtocol { }

let intType: Int.Type = Int.self
let stingType = String.self
let classType = SomeClass.self
let protocolProtocol = SomeProtocol.self

var someType: Any.Type

someType = intType
print(someType)
//Int

someType = stingType
print(someType)
// String

someType = classType
print(someType)
// SomeClass

someType = protocolProtocol
print(someType)
//SomeProtocol

위의 코드를 확인해보면 SomeProtocol, SomeClass 등의 메타 타입이 하나의 값으로 취급되어 someType 변수에 할당될 수 있음을 확인할 수 있습니다. 또, Int, String도 스위프트에서 구조체로 구현한 타입이므로 메타 타입을 값으로 취급해 할당할 수 있음을 확인할 수 있습니다.

만약 프로그램 실행 중 인스턴스의 타입을 표현한 값을 알아보고자 한다면 type(of:) 함수를 사용합니다.

예시) type(of: SomeInstance).self라고 표현하면 someInstance의 타입을 값으로 표현한 값을 반환합니다.

💡 인스턴스 self와 타입 self의 의미

인스턴스.self는 인스턴스 그 자체를,
String.self는 String 타입을 나타내는 값입니다.

print(type(of: coffee) == Coffee.self) // true
print(type(of: coffee) == Americano.self) // false
print(type(of: coffee) == Latte.self) // false

다운캐스팅

다음 코드를 확인해봅시다.

let 라떼안에커피있다: Coffee = Latte(: "메이플")

‘라떼안에커피있다’ 인스턴스는 Latte 클래스의 인스턴스로 만들어졌지만 Coffee 행세를 할 수 있습니다.

print(라떼안에커피있다.description)

// 저희 집 커피 원두는 에티오피아이고
// 이 커피는 메이플 라떼입니다.2 샷입니다.

description은 override 했기 때문에 Latte의 description이 나타나지만

print(라떼안에커피있다.만드는법())
print(라떼안에커피있다.)

Latte클래스 내부의 메소드 ‘만드는법()’와 Latte 클래스의 프로퍼티인 ‘맛'에는 접근할 수 없습니다.

만드는법()메소드와 ‘맛'프로퍼티에 접근하기 위해서는 Latte 타입으로 변수의 타입을 변환해주어야하는데 이를 타입 캐스팅을 해주어야 합니다.

이때는 Coffee 클래스가 Latte 클래스의 부모클래스이기 때문에 Latte 타입 변환하는 것을 다운 캐스팅이라고 합니다.

그러면 Latte 클래스에서 Coffee 클래스로 타입 변환하는 것을 무엇이라고 할까요? 이는 추측대로 업 캐스팅이라고 합니다.

  • 다운 캐스팅 연산자 as?, as! 다운 캐스팅은 실패 가능성이 있기 때문에 as?와 as!가 있는 것이고 as?의 경우 다운 캐스팅에 실패할 경우 nil을 반환합니다.
    이를 if let으로 옵셔널 추출을 해보겠습니다.
    if let newValue = 라떼안에커피있다 as? Latte {
        print(newValue.만드는방법())
        print(newValue.)
    }
    
    // 잔에 2샷을 넣고 데운 우유 위에 메이플 시럽을 뿌려주세요.
    // 메이플
    as!는 강제 연산자로 확실한 경우가 아니라면 사용을 지양하며 실패할 경우 런타임 오류가 발생합니다.
  • 업 캐스팅 연산자 as
    let americano: Americano = Americano(iced: true)
    print(americano.howToMake())
    // 얼음물 위에 샷을 추가하면 아메리카노,
    // 샷을 넣고 그 위에 얼음 넣고 물 넣으면 룽고
    
    let newCoffee = americano as Coffee
    print(newCoffee.howToMake())
    // error: value of type 'Coffee' has no member 'howToMake'

💡 타입캐스팅의 의미
캐스팅은 실제로 인스턴스를 수정하거나 값을 변경하는 작업이 아닙니다.
인스턴스는 메모리에 똑같이 남아 있을 뿐, 인스턴스를 사용할 때 어떤 타입으로
다루고 어떤 타입으로 접근해야 할지 판단할 수 있도록 컴퓨터에 힌트를 주는 것뿐입니다.

Any, AnyObject의 타입캐스팅

Any는 함수타입을 포함한 모든 타입을 뜻하고, AnyObject는 클래스 타입만을 뜻합니다.

💡 Any와 AnyObject를 사용하면 예기치 못한 오류가 발생할 확률이 높아지므로 되도록이면 사용을 지양하는 것이 좋습니다.

💡 옵셔널과 Any
Any 타입은 모든 값 타입을 표현하고 더불어 옵셔널 타입도 표현할 수 있습니다.
하지만 Any 타입의 값이 들어와야 할 자리에 옵셔널 타입의 값이 위치한다면 스위프트 컴파일러는 경고를 합니다. 의도적으로 옵셔널 값을 Any 타입의 값으로 사용하고자 한다면 as 연산자를 사용하여 명시적 타입 캐스팅을 해주면 경고 메시지를 받지 않습니다.업로드중..

자료 출처: 야곰 스위프트 프로그래밍 3판

"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."
profile
iOS 개발자입니다.

0개의 댓글