Type Casting in Swift

권승용(Eric)·2024년 10월 28일

TIL

목록 보기
1/38

타입 검사

  • 타입 검사 오퍼레이터 : is
  • 해당 오퍼레이터를 사용해 인스턴스가 특정한 타입 또는 타입의 서브클래스 타입인지 확인 가능하다.
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)
    }
}

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"

다운캐스팅

  • 클래스 타입의 프로퍼티는 사실 서브클래스 인스턴스를 가리키고 있을 수도 있다.
  • 이 때 타입 캐스팅 오퍼레이터 (as? 또는 as!)를 사용해 서브클래스 타입으로 다운캐스팅 할 수 있다.
  • 다운캐스팅은 실패 가능한 연산이기 때문에 as? 또는 as! 두 가지 연산자를 제공한다.
  • as?는 실패 시 nil을 반환하기 때문에 옵셔널 타입을 반환하고, 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
  • 캐스팅은 인스턴스를 변경시키지 않는다. 인스턴스는 똑같이 유지된다.

업캐스팅

  • 부모 클래스 타입으로의 업캐스팅을 통해 타입 변환도 가능하다.
class Animal { }
class Dog: Animal { }

let myDog = Dog()
let myAnimal = myDog as Animal  // Upcasting
  • 업캐스팅은 as 키워드로 수행 가능하며 항상 성공한다.

Any와 AnyObject의 타입 캐스팅

  • Swift는 구체 타입이 아닌 타입으로 작업할 수 있는 두 가지 특수한 타입을 제공
  • Any : 함수 타입을 포한한 어떤 타입의 인스턴스던 표현 가능
  • AnyObject : 어떤 클래스의 인스턴스던 표현 가능
  • Any와 AnyObject는 꼭 필요한 경우에만 사용.
  • 구체 타입을 제공할 수 있다면 제공하는 것이 항상 좋음
  • Any 타입을 활용하면 아래와 같이 서로 다른 타입을 하나의 배열에 넣을 수 있다.
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)" })
  • Any 또는 AnyObject 타입의 구체 타입을 알기 위해선 is 또는 as 패턴 사용 가능.
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에 옵셔널 타입을 곧바로 할당할 수 없다.
  • 할당하고자 한다면 아래와 같이 타입 캐스팅이 필요.
let optionalNumber: Int? = 3
things.append(optionalNumber)        // Warning
things.append(optionalNumber as Any) // No warning
profile
ios 개발자에용

0개의 댓글