-
Type CastingiOS/Swift 공식문서 2022. 2. 23. 15:29
Type Casting
인스턴스의 타입을 확인하거나, 인스턴스를 해당 클랫스 계층구조의 다른 superclass나 subclass로 취급하는 방법이다. Swift에서는
is
와as
연산자로 구현되어 있다.
Defining a Class Hierarchy for Type Casting
타입 캐스팅에 대한 설명을 위해 우선 하나의 계층구조에 들어가는 클래스들을 정의하자. 3개의 클래스는 다음과 같다.
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) } }
그 다음으로 위의 클래스들의 인스턴스들을 담는 배열인
library
를 선언하자.Movie
,Song
클래스들은MediaItem
이라는 공통 superclass가 있기 때문에library
의 타입은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
배열에 내부에는Movie
와Song
의 인스턴스들이 있지만, 배열의 element들에 대하여 반복문을 수행하면, 우리가 되돌려받는 각 아이템은MediaItem
타입을 가지게 된다. 인스턴스들의 원래 타입으로 작업을 하려면, 각 인스턴스의 타입을 확인하고 다른 타입으로 downcasting해야 한다.
Checking Type
인스턴스가 특정 subclass 타입의 인스턴스인지 확인하려면
is
연산자를 사용한다.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
특정 클래스 타입의 상수/변수는 실제로는 subclass의 인스턴스를 참조할 수 있다. 이러한 경우, 타입 캐스팅 연산자(
as?
혹은as!
)를 사용하여 해당 subclass 타입으로 downcasting할 수 있다.
downcasting이 실패할 가능성도 있기 때문에, 타입 캐스팅 연산자는 2개의 형태로 정의된다.
as?
연산자는 downcasting하려는 타입의 optional 값을 반환한다.as!
연산자는 downcasting을 시도하고 강제 unwrapping을 한다. downcasting이 성공할지 확신할 수 없다면as?
를 사용하자.as!
의 경우 downcasting이 실패할 경우 런타입 에러를 발생시킨다.
as?
연산자의 결과는 optional 값이기 때문에 optional binding과 같이 사용할 수 있다.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
Type Casting for Any and AnyObject
Swift는 불특정 타입들에 대하여 작업을 할 수 있도록 특별한 타입을 제공한다.
a.
Any
는 함수 타입을 포함한 모든 타입의 인스턴스를 나타낼 수 있다.
b.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
타입의 컬렉션에서 작업을 할 경우 각 element의 타입을 확인하고 작업해야 한다.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
note
Any
타입은 optional 타입도 포함한다. Swift는Any
타입의 값을 넣어야 하는 자리에 optional 값을 넣는 경우 경고를 한다.Any
값으로 반드시 optional 값을 사용해야 한다면 optional 타입을Any
로 변환하기 위해as
연산자를 사용할 수 있다.let optionalNumber: Int? = 3 things.append(optionalNumber) // Warning things.append(optionalNumber as Any) // No warning
Reference
https://docs.swift.org/swift-book/LanguageGuide/TypeCasting.html
'iOS > Swift 공식문서' 카테고리의 다른 글
Extensions (0) 2022.02.23 Nested Types (0) 2022.02.23 Concurrency (0) 2022.02.23 Error Handling (0) 2022.02.22 Optional Chaining (0) 2022.02.22