Swift - 타입캐스팅

임성빈·2022년 4월 8일

Swift

목록 보기
17/26
post-thumbnail

타입캐스팅


타입캐스팅은 인스턴스의 타입을 확인하거나 인스턴스를 같은 계층에 있는 다른 Superclass나 Subclass로 취급하는 방법이다. 타입캐스팅에는 is 와 as 두 연산자를 사용한다. 타입캐스팅을 이용하면 특정 프로토콜을 따르는지 확인할 수 있다.


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

다음은 타입캐스팅의 동작을 확인하기 위한 예제이다.

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

MediaItem 이라는 클래스를 선언했는데 이 클래스를 서브클래싱해서 두개의 다른 서브클래스를 만들어보자.

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

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

MediaItem 클래스의 서브클래스 Movie 와 Song 두개의 클래스를 선언했다. 마지막으로 이 Movie 와 Song 두개의 클래스를 아이템으로 갖는 library 배열을 선언한다.

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 가 갖고 있는 Movie , Song 인스턴스의 공통 부모는 MediaItem 이기 때문에 library 는 타입 추론에 의해 [MediaItem] 배열의 형을 갖게 된다. library 를 훈회하면 배열의 아이템은 Movie , Song 타입이 아니라 MediaItem 타입이라는 것을 확인할 수 있다. 타입 지정을 위해서는 downcasting 을 이용해야한다.


형 확인

is 연산자를 이용해 특정 인스턴스의 타입을 확인할 수 있다. 아래 코드는 library 배열을 순회하고 아이템이 특정 타입일 때마다 그 숫자를 증가하는 예제 코드이다.

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" 출력

다운캐스팅

특정 클래스 타입의 상수나 변수는 특정 서브클래스의 인스턴스를 참조하고 있을 수 있다. as? 와 as! 연산자를 이용해 어떤 타입의 인스턴스인지 확인할 수 있다. as? 는 특정 타입이 맞는지 확신할 수 없을 때 사용하고 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

library 배열의 mediaItem 이 Movie 인스턴스일 수도 있고 Song 인스턴스일 수도 있기 때문에 다운캐스팅을 위해 as? 연산자를 사용했습니다.


Any, AnyObject의 타입 캐스팅

Swift에서는 두가지 특별한 타입을 제동한다.

  • Any: 함수 타입을 포함해서 모든 타입을 나타낸다.

  • AnyObject: 모든 클래스 타입의 인스턴스를 나타낸다.

Any 타입의 예제다. things 라는 Any 타입 배열을 선언해 여러 타입의 값을 저장합니다. 여기에는 Int , String , 함수, 클로저까지 포함된다.

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

things 를 순회하며 타입캐스팅이 되는지 switch case 문에 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")
    }
}

Int , Double 뿐만 아니라 튜플, 함수도 Any 타입에 포함될 수 있다는 것을 확인할 수 있다.

profile
iOS 앱개발

0개의 댓글