[swift]코드로 보는 is, as, as?, as! - Type Casting

okstring·2021년 2월 21일
0

Type Casting

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은 인스턴스의 유형을 확인하거나 해당 인스턴스를 다른 수퍼 클래스 또는 하위 클래스로 취급하는 방법입니다

타입 캐스팅을 위한 클래스 계층구조 선언

참고

import Foundation

class MediaItem {
    var name: String
    init(name: String) {
        self.name = name
    }
}

class Movie: MediaItem {
    var director: String
    init(name: String, director: String) {
        self.director = director
        super.init(name: name)
    }
}

class Song: MediaItem {
    var artist: String
    init(name: String, artist: String) {
        self.artist = artist
        super.init(name: name)
    }
}

형 확인 (Checking Type)

is연산자를 이용해 특정 인스턴스의 타입을 확인할 수 있습니다.

let library = [
    Movie(name: "Casablanca", director: "Michael Curtiz"),
    Song(name: "Blue Suede Shoes", artist: "Elvis Presley"),
    Movie(name: "Citizen Kane", director: "Orson Welles"),
    Song(name: "The One And Only", artist: "Chesney Hawkes"),
    Song(name: "Never Gonna Give You Up", artist: "Rick Astley"),
]

var movieCount = 0
var songCount = 0

for item in library {
    if item is Movie {
        movieCount += 1
    } else if item is Song {
        songCount += 1
    }
}

print("Media library contains \(movieCount) movies and \(songCount) songs")
// Media library contains 2 movies and 3 songs

여기서 libraryMediaItem의 인스턴스가 담겨있다고 말해준다. type Inference으로 당연한거지만 타입캐스팅을 다룰 때면 이상하게 인지하고 있지 못했다.

as 연산자 사용

as는 해당 타입이 캐스팅이 되는지 바로 알려줍니다. 여기서 as의 실행 시점을 확인할 수 있습니다.

let fly = Movie(name: "Fly!", director: "Ji")

print((fly as MediaItem).name) // Fly!
print((fly as Movie).name) // // Fly!
//print((fly as Song).name) // Cannot convert value of type 'Movie' to type 'Song' in coercion

그러면 아까 library와 같이 (형 확인의 is의 방법도 있지만) 배열이나 해시테이블 등 특정할 수 없다면 어떻게 할까? as?as!를 활용하면 됩니다.

다운캐스팅 (Downcasting)

as?as!연산자를 이용해 어떤 타입의 인스턴스인지 확인할 수 있습니다. as?는 특정 타입이 맞는지 확신할 수 없을때 사용하고 as!는 특정 타입이라는 것이 확실한 경우에 사용합니다. 다음 예제는 library배열의 mediaItemMovie 인스턴스 일수도 있고 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

정상적으로 캐스팅이 잘 되는걸 확인할 수 있습니다. if let을 사용한 것처럼 옵셔널로 반환이 됩니다

print(library[0] as? Movie)
//Optional(TestAndTest.Movie)

as! 연산자 사용

as!으로 다운캐스팅을 했는데 지정한 타입이 아니라면 런타임 에러가 발생합니다.

print(library[0] as! Song)
//런타임 에러!!

as, as?, as!의 차이점

as는 컴파일타임에, as?와 as!는 런타임에 실행된다고 합니다.

  • 컴파일 타임 : 소스코드(swift파일)을 작성하고 compile이라는 과정을 통해 기계어코드로 변환 되어 실행 가능한 프로그램이 되게 만드는 편집 과정
  • 런타임 : 컴파일 과정을 마친 프로그램이 사용자에 의해 실행되어 지고 응용프로그램이 동작될때의 시간

reference

https://zeddios.tistory.com/265

https://gaki2745.github.io/swift/2019/10/02/Swift-Basic-04/

https://docs.swift.org/swift-book/LanguageGuide/TypeCasting.html

profile
step by step

0개의 댓글