Mobile/ios & swift

[Swift 4] 타입 캐스팅 (Type Casting)

버리야 2018. 4. 8. 22:18
반응형
이 포스팅은 The Swift Programming Language (Swift 4.1) 의 Type Casting 문서를 보고 이해하며 제 것으로 만들면서 정리해 놓은 문서입니다.

원문 


https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TypeCasting.html#//apple_ref/doc/uid/TP40014097-CH22-ID338




타입 캐스팅(Type Casting)



타입 캐스팅은 인스턴스의 타입을 체크하거나 해당 인스턴스를 고유한 클래스 계층 구조의 다른 수퍼 클래스나 서브 클래스로 처리하는 방법이다.


Swift에서의 타입 캐스팅은 is와 as 연산자로 구현된다. 이 두 연산자는 값 타입을 확인하거나 값을 다른 타입으로 변환하는 간단하고 표현적인 방법을 제공한다.


또한, 프로토콜 준수하는지 확인하기(Checking for Protocol Conformance)에서 설명된것처럼, 프로토콜을 준수하는지 확인하는데 타입 캐스팅을 사용 할 수 있다.



타입 변환에 대한 클래스 계층 정의하기(Defining a Class Hierachy for Type Casting)


특정 클래스 인스턴스의 타입을 확인하고 같은 계층 구조의 다른 클래스의 인스턴스로 변환하기 위해, 클래스와 서브 클래스의 계층 구조와 함께 타입 캐스팅을 사용 할 수 있다.


아래 예제는 타입 캐스팅을 사용하기 위해, 클래스의 계층구조와 이러한 클래스의 인스턴스를 포함하는 배열을 정의한다.

 

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

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]





타입 확인 (Checking Type)


타입 확인 연산자(is)를 사용하여 인스턴스가 특정 서브 클래스 유형인지 확인할 수 있다. 


타입 확인 연산자(type check operator)는 인스턴스가 해당 서브 클래스 형식 인 경우 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!)로 서브 클래스 타입을 다운캐스트(downcast) 할 수 있다.

다운 캐스트가 실패 할 수 있기 때문에, 타입 캐스팅 연산자는 두가지 형태가 있다.


조건부 형식인, as?은 타입의 다운캐스트(downcast)를 시도해서 옵셔널 값을 반환한다.

강제 형식인, as!은 다운캐스트(downcast)와 강제 언래핑(force-unwraps)을 시도한 결과를 반환한다.


타입 캐스팅 연산자(as?)의 옵셔널 형식 사용은 다운캐스트가 성공한다는 것을 확신할 수 없을때 한다.

타입 캐스팅 연산자의 옵셔널 형식은 항상 옵셔널 값을 반환하고 다운캐스트가 가능하지 않으면 nil 값을 반환할 것이다. 성공적인 다운캐스트를 위해 검사를 해야한다.


타입 캐스팅 연산자(as!)의 강제 형식은 다운캐스트가 항상 성공한다고 확신할 때 사용한다.

형 변환 연산자의 강제 형식은 클래스 타입이 정확하지 않으면 런타입 에러를 발생할 수 있다.



다음은 library 안에 각각의 MediaItem을 반복하여 각각의 항목에 적절한 설명을 출력한다. 이를 하기 위해 각각의 항목은 Movie나 Song으로 접근할 필요가 있지만 MediaItem으로 할 필요는 없다. 각 설명을 위해서 Movie나 Song의 director이나 artist 속성에 접근 할 필요가 있다.



아래 예제에서, 배열의 각 항목은 Movie또는 Song이 될 수 있다.



각 항목에서 사용 할 실제 클래스를 미리 알지 못하고, 반복문에서 다운캐스트를 확인하기 위해 조건부 형식의 타입 캐스팅 연산자(as?)를 사용하는게 적절하다.

 

for item in library {
    if let movie = item as? Movie { //item을 Movie로 다운캐스트(downcast) 시도. 결과는 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




Any와 AnyObject를 위한 타입 캐스팅 (Type Casting for Any and AnyObject)


Swift는 지정되지 않은 타입 작업을 위해 두개의 특별한 타입을 제공한다.

- Any는 함수 타입도 포함한, 모든 타입의 인스턴스를 표현 할 수 있다.

- AnyObject는 모든 클래스 타입의 인스턴스를 표현 할 수 있다.


아래 예제는 함수 타입과 클래스 타입이 아닌 타입을 포함하여, 다양한 다른 타입으로 섞어 작업하기 위해 Any 사용하는 예제이다. 


이 예제는 Any 타입의 값을 저장 할 수 있는 things를 생성한다.


 

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")) //Movie
things.append({ (name: String) -> String in "Hello, \(name)" }) //클로저


Any 또는 AnyObject타입으로 된 상수와 변수의 특정 타입을 발견하기 위해, switch 문의 case에서 is 또는 as 패턴을 사용 할 수 있다.

아래 예제는 things 배열안의 항목을 for문을 반복하고 각 항목의 타입을 switch문으로 조회한다.

몇가지 switch문의 case는 값을 출력 할 수 있도록 특정 타입의 상수로 일치한 값을 바인딩(bind)한다.

 

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


반응형