[Swift] 18. Type Casting

도윤·2021년 8월 10일
0

Swift

목록 보기
16/21

Type casting은 다른 슈퍼클래스나 서브클래스로써 인스턴스를 취급하거나 인스턴스의 타입을 확인하는 방식이다. 타입캐스팅은 is,as 연산자로 실행된다.

Defining a Class Hierarchy for Type Casting

클래스 및 하위 클래스의 계층과 함께 유형 주조를 사용하여 특정 클래스 인스턴스의 유형을 확인하고 해당 인스턴스를 동일한 계층 내의 다른 클래스에 캐스팅할 수 있습니다.

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

MediaItem의 base class이다.

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)
    }
}

MediaItem클래스의 서브클래스이다.

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")
]
// the type of "library" is inferred to be [MediaItem]

library배열의 타입은 미디어 클래스이다. 원래의 유형으로 사용하기 위해서는 다운캐스팅을 해야한다.

Checking Type

타입을 확인하는 연산자 is를 사용하여 인스턴스의 서브클래스가 무엇인지 확인할 수 있다. 만약 subclass type의 인스턴스와 맞다면 true,아니면 false를 반환한다.

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")
// Prints "Media library contains 2 movies and 3 songs

Downcasting

형식 캐스팅 연산자(as? 또는 as!)를 사용하여 하위 클래스 유형으로 다운캐스트할 수 있습니다.
다운캐스팅이 실패하면 타입 캐스팅 연산자가 두 가지의 형태로 나타난다. as?는 downcast하고자하는 타입의 옵셔널 값이 반환된다. as!는 강제로 down캐스팅을 하는 것이다.

as? : 다운캐스팅의 성공 여부가 확실하지 않는다면 as?를 사용하면 된다. 항상 optional type이 반환되며, 다운캐스팅이 실패하면 nil값이 반환한다.

as! : 다운캐스팅이 무조건 성공한다는 것이 확실하다면 사용. 만약 다운캐스팅이 실패한다면 runtime error가 발생한다.

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

item이 Movie인지 Song인지 확실하지 않는다면 as?를 사용해야 한다. 결과는 Optional Value가 나오기 때문에 Optional binding으로 값을 얻는다.

만약 성공한다면 item은 Movie인스턴스나 Song의 인스턴스로 사용된다.

Type Casting for Any and AnyObject

확실치 않는 타입과 작업하기 위한 특별한 타입이 2가지가 제공된다.

  • Any는 함수 타입을 포함하여 모든 타입의 인스턴스를 표현할 수 있다.
  • AnyObejct는 class type의 인스턴스를 표현할 수 있다.

Any 및 AnyObject는 제공하는 동작과 기능이 명시적으로 필요한 경우에만 사용해야 한다.
가급적이면 코드에서 작업할 유형을 구체적으로 지정하는 것이 좋다.

var things = [Any]()

things.append(0)
things.append(0.0)
things.append(42)
things.append(3.14159)
things.append("hello")
things.append((3.0, 5.0))
things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman"))
things.append({ (name: String) -> String in "Hello, \(name)" })

이 배열은 정수형,더블형,string,class,function이 포함되어 있다.

Any 또는 AnyObject 유형으로만 알려진 상수 또는 변수의 특정 유형을 검색하려면 스위치 문의 경우 is 또는 패턴을 사용할 수 있습니다.

for thing in things {
    switch thing {
    case 0 as Int:
        print("zero as an Int")
    case 0 as Double:
        print("zero as a Double")
    case let someInt as Int:
        print("an integer value of \(someInt)")
    case let someDouble as Double where someDouble > 0:
        print("a positive double value of \(someDouble)")
    case is Double:
        print("some other double value that I don't want to print")
    case let someString as String:
        print("a string value of \"\(someString)\"")
    case let (x, y) as (Double, Double):
        print("an (x, y) point at \(x), \(y)")
    case let movie as Movie:
		print("a movie called \(movie.name), dir. \(movie.director)")
    case let stringConverter as (String) -> String:
        print(stringConverter("Michael"))
    default:
        print("something else")
    }
}

// zero as an Int
// zero as a Double
// an integer value of 42
// a positive double value of 3.14159
// a string value of "hello"
// an (x, y) point at 3.0, 5.0
// a movie called Ghostbusters, dir. Ivan Reitman
// Hello, Michael

Any타입은 옵셔널 타입을 포함한 어떠한 타입의 값도 표현할 수 있다. 만약 Any로 예상되는 타입의 값의 옵셔널 값을 사용하면 경고가 발생한다. 만약 Any value로써 옵셔널 값을 사용할 필요가 있다면 as Any를 명시하여 사용해야 한다

let optionalNumber: Int? = 3
things.append(optionalNumber)        // Warning
things.append(optionalNumber as Any) // No warning’

0개의 댓글