[Xcode / Swift] Type Casting(형변환) 관련 | is, as, as?, as! 차이점

형변환은 Instance의 타입을 확인하거나, Instance를 superclass 혹은 subclass로 취급하여 처리하기 위해 필요한 작업.

Type casting is a way to check the type of an instance, or to treat that instance as a different superclass or subclass from somewhere else in its own class hierarchy.

출처 – Type Casting – Swift Official Document

is와 as로 구별되며, is는 Instance의 타입을 확인하는데 사용되며, as는 Instance의 형변환 작업에 이용되는 명령어이다.


?와 !와 함께 쓰이면서 혼동을 일으키는 경우가 있으므로 아래와 같이 정리함. 다음 예시 코드를 이용해서 차이를 설명함.

class Creature
{
    var age :Int?
    
    init(age :Int?)
    {
        if let age = age
        {
            self.age = age
        }
    }
}

class Human : Creature
{
    var name :String?
    
    init(name :String?, age :Int?)
    {
        if let name = name
        {
            self.name = name
        }
        super.init(age: age)
    }
}

class Animal : Creature
{
    var weight :Int?
    
    init(weight: Int?, age :Int?)
    {
        if let weight = weight
        {
            self.weight = weight
        }
        super.init(age: age)
    }
}


var creature = [Animal(weight : 12, age: 5), Human(name : "Kim", age: 30)]
  • Creature란 Superclass를 정의하고 Human과 Animal Class는 Subclass로써 Creature Class를 상속
  • creature라는 instance 배열을 만들어, Animal 개체와 Human 개체를 각각 저장. creature의 형은 Creature.

형 체크 – is

Bool 타입을 Return 하며, 지정된 Instance가 특정 Class인지를 판별.

 고로, 다음과 같이 사용할 수 있다.

for item in creature
{
    if item is Animal
    {
        print("Current Item is Animal")
    }
    else
    {
        print("Current Item is NOT Animal")
    }
}

Downcasting – as? as!

상위 계층(부모 계층)에서 하위 계층(자식 계층)으로의 Downcasting임. Downcast 방법에는 as?, as! 두가지가 있다. Swift 1.2 이후 부터 as는 Upcast만 가능하기 때문에 제외한다. ?와 !의 수행하는 기능은 근본적으로 같지만 그 결과물에 차이가 있다.

  • ? : Optional 선택적
  • ! : Forced 강제적

as?는 말그대로 선택적이며, Optional Value를 Return 해준다. Downcast가 가능하지 않다면, nil값이 반환된다. Downcast에 성공적일지 아닐지가 불확실하다면 as?를 선택해주는 것이 현명하다. as?에 의해 형변환된 Instance를 그대로 출력해보면 Optional() Value가 나오는 것을 알 수 있다.

creature[0] as? Animal //Animal
creature[0] as? Human //nil

print(creature[0] as? Animal) //Optional(__lldb_expr_46.Animal) 출력

as!는 강제적으로 Downcast 한다. 또한, Downcast가 성공적이지 않을 시, runtime error를 일으킨다. 절때 실패할 수 없는 Downcast에서 사용하는 것이 적당하다. as!에 의해 Downcast된 Instance를 출력 시, Optional 값이 강제적으로 unwrap된 것을 알 수 있다.

creature[0] as! Animal //Animal
creature[0] as! Human //runtime error

print(creature[0] as! Animal) //__lldb_expr_48.Animal 출력

간단하게 이야기해서, as?와 as!는 그 동작(Downcast)이 같다. 오류가 나지 않는 코드라면 as?와 as!가 항상 같은 결과물을 낸다. 하지만, 위에 설명되어 있듯이 “Sure/Not Sure”를 구분지어 각각 “!/?”를 사용하는 것이 현명하다.


Upcasting – as as? as!

하위 계층(자식 계층)에서 상위 계층(부모 계층)으로의 UpCasting임. as as? as! 모두 사용가능하다. 위에서 설명한 것과 같이 선택적, 강제적의 차이가 있다.

Upcasting에 성공한 코드

let downcasted_creature = creature[0] as! Animal //Animal
let upcasted_downcasted_creature = downcasted_creature as Creature //Creature

Upcasting에 실패하였을 때

  • as : 오류 반환
  • as? : nil값 반환
  • as! : 오류 반환
let downcasted_creature = creature[0] as! Animal //Animal
let upcasted_downcasted_creature = downcasted_creature as Human //오류
let upcasted_downcasted_creature = downcasted_creature as? Human //nil
let upcasted_downcasted_creature = downcasted_creature as! Human //오류

참조

댓글 남기기