IOS/Swift

[TIL] Swift. Type Casting(feat. is, as)

Type Casting

코딩 강의를 보면서 is 또는 as가 언제 쓰이게 되고 왜 이렇게 쓰이는지 궁금해서 정리하게 되었습니다.
  • Type Casting?
    1. 스위프트는 다른 프로그래밍 언어에서 대부분 지우언하는 암시적 데이터 타입 변환은 지원하지 않습니다.
    2. 아래의 예시는 Int(value)라는 형태의 데이터 타입으로 형태를 변경해주는데, 이는 이니셜라이저와 같습니다.
    3. 즉, 기존의 데이터를 전달인자로 받아 새로운 Int 구조체의 인스턴스를 생성하게 됩니다.
    4. 스위프트에서는 이를 타입 캐스팅이 아니라, 이니셜라이즈를 통해 새로운 인스턴스를 생성하는 과정이라합니다.
var value: Double = 3.3
var convertedValue: Int = Int(value)
convertedValue = 5.5 // error!
  • 스위프트의 타입캐스팅
    • 스위프트에서의 타입캐스팅은 인스턴스의 타입을 확인하거나 자신을 다른 타입의 인스턴스처럼 사용할 수 있는 방법입니다.
    • 스위프트의 타입 캐스팅은 두가지가 있습니다.
    • 타입을 확인하는 is
    • 자식 클래스로 변환하는 다운캐스팅 as
///Coffee 클래스와 Coffee클래스를 상속받은 Latte와 Americano  클래스
class Coffee{
    let name: String
    let shot: Int
    
    var description: String{
        return "\(shot) shot(s) \(name)"
    }
    
    init(shot: Int) {
        self.shot = shot
        self.name = "coffee"
    }
}

class Latte: Coffee{
    var flavor: String
    
    override var description: String{
        return "\(shot) shot(s) \(flavor) latte"
    }
    
    init(flavor: String, shot: Int) {
        self.flavor = flavor
        super.init(shot: shot)
    }
}

class Americcano: Coffee{
    let iced: Bool
    
    override var description: String{
        return "\(shot) shot(s) \(iced ? "iced" : "hot") americano"
    }
    
    init(shot: Int, iced: Bool) {
        self.iced = iced
        super.init(shot: shot)
    }
    
}
  • 위에 선언된 클래스를 활용해서 인스턴스를 만들고 is를 사용해 확인해 보겠습니다

is. 타입 확인

let coffee: Coffee = Coffee(shot: 1)
print(coffee.description) // 1 shot(s) coffee

let myCoffee: Americcano = Americcano(shot: 2, iced: false)
print(myCoffee.description) // 2 shot(s) hot americano

let yourCoffee: Latte = Latte(flavor: "green tea", shot: 3)
print(yourCoffee.description) // 3 shot(s) green tea latte

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

print(myCoffee is Coffee) // true
print(yourCoffee is Coffee) // true

print(myCoffee is Latte) // false
print(yourCoffee is Latte) // true
  • 위의 결과처럼 최상위 클래스(Coffee)는 자식클래스의 Americcano, Latte를 is 로 대입한결과 false로 출력되는 것을 확인할수있지만
  • Americcano, Latte는 is로 Coffee를 대입하면 true가 출력되는 것을 확인할수 있습니다.
  • 부모는 자식 타입 x, 자식은 부모타입 o

as. 다운캐스팅

let actingConstant: Coffee = Latte(flavor: "vanilla", shot: 2)
print(actingConstant.description) // 2 shot(s) vanilla latte
  • 위와 같은 자식클래스가 부모클래스로 변수선언이 되었을 경우 아무 문제없이 인스턴스가 생성되기 때문에, Class Latte타입의 인스턴스를 참조해야 할 경우 문제가 생길수 있습니다. 
  • 따라서 이런경우 actingConstant 의 타입을 Latte로 변경해 주어야 하는데 이럴경우 사용되는 키워드가 as입니다
  • 하지만 다운캐스팅은 위와같은 예시처럼 false가 출력될수 있기 때문에 기본적인 리턴값이 옵셔널입니다.
  • 따라서 if나 guard를 사용해서 사용해 주어야합니다.
  • 그러나 확신할수 있는경우 as!를 사용할수도 있습니다.
타입캐스팅은 실제로 인스턴스를 수정하거나 값을 변경하는 작업이 아닙니다. 인스턴스는 메모리에는 똑같이 남아있을 뿐입니다.다만 인스턴스를 사용할 때 어떤 타입으로 다루고 어떤 타입으로 접근해야 할지 판단할 수 있도록 컴퓨터에 힌트를 주는 것입니다.

Any, AnyObject 타입캐스팅

  • Any는 함수타입을 포함한 모든타입을 뜻하고, AnyObject는 클래스 타입만을 뜻합니다. 
  • 반환되는 타입이 Any 또는 AnyObject인 경우 전달받는 데이터가 어떤 타입인지 확인하고 사용해야 합니다. 
    스위프트는 암시적 타입 변환을 허용하지 않기 때문입니다.
  • 아래의 코드는 item이 어떤 타입인지 판단하며 해당 타입의 인스턴스로 사용할수 있도록 하는 코드입니다.
  • Any의 경우 들어오는 타입의 케이스에 맞추어 스위치 구문으로 is나 as를 활용하여 사용할수 있습니다.
func castTypeToAppropriate(item: AnyObject){
    if let castedItem: Latte = item as? Latte{
        print(castedItem.description)
    }else if let castedItem: Americcano = item as? Americcano{
        print(castedItem.description)
    }else if let castedItem: Coffee = item as? Coffee{
        print(castedItem.description)
    }else{
        print("Inknown Type")
    }
}

castTypeToAppropriate(item: coffee) // 1 shot(s) coffee
castTypeToAppropriate(item: myCoffee) // 2 shot(s) hot americano
castTypeToAppropriate(item: yourCoffee) // 3 shot(s) green tea latte
castTypeToAppropriate(item: actingConstant) // 2 shot(s) vanilla latte
팁.

옵셔널과 Any
Any타입은 모든 값 타입을 표현합니다. 더불어 옵셔널 타입도 표현할 수 있습니다. 그런데도 Any타입의 값이 들어와야 할 자리에 옵셔널 타입의 값이 위치한다면 스위프트 컴파일러는 경고를 합니다.
의도적으로 옵셔널 값을 Any타입의 값으로 사용하고자 한다면 as 연산자를 사용하여 명시적 타입 캐스팅을 해주면 경고메시지를 받지 않습니다.
let optionalValue: Int? = 100 print(optionalValue) // warning print(optionalValue as Any) // 경고 없음

자료출처
https://velog.io/@wimes/%ED%83%80%EC%9E%85%EC%BA%90%EC%8A%A4%ED%8C%85

참고페이지

jusung.gitbook.io/the-swift-language-guide/language-guide/18-type-casting

'IOS > Swift' 카테고리의 다른 글

Codable & Encodable  (0) 2020.10.21
[TIL] Swift. Closure  (0) 2020.10.19
[TIL] Swift. GCD (Grand Central Patch)  (0) 2020.10.17
[TIL] Swift. Frame and Bounds  (0) 2020.10.15
[TIL] Swift. awakeFromNib  (0) 2020.10.14