본문 바로가기

문법

[Swift] 타입(Type Casting)캐스팅이란?

- Reference

- https://docs.swift.org/swift-book/LanguageGuide/TypeCasting.html

 

Type Casting — The Swift Programming Language (Swift 5.6)

Type Casting Type casting is a way to check the type of an instance, or to treat that instance as a different superclass or subclass from somewhere else in its own class hierarchy. Type casting in Swift is implemented with the is and as operators. These tw

docs.swift.org

 

[카테고리]

 

- Defining a Class Hierarchy for Type Casting

- Checking Type

- Downcasting

- Type Casting for Any and AnyObject

 

[정의]

타입 캐스팅은 인스턴스의 타입을 확인하는 방법이다.

또는 인스턴스를 자체 클래스 계층구조의 다른 위치에서 다른 수퍼 클래스 or 하위 클래스로 취급한다.

[표현방법]

is, as

유형 캐스팅은 is 및 as 연산자로 구현되며 값의 유형을 확인하거나 다른 유형으로 캐스팅하는 간단한 표현방법이다.

 

[특징]

- 프로토콜을 준수하는지 여부를 확인할 수도 있다.

- 캐스팅은 실제로 인스턴스를 수정하거나 값을 변경하지 않는다. 기본 인스턴스는 동일하게 유지됩니다. 단순히 캐스트된 유형의 인스턴스로 처리되고 엑세스 됩니다.

 

# 유형 캐스팅을 위한 class 계층 정의

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: "기생충", director: "봉준호"),

    Song(name: "Y", artist: "지코"),

    Movie(name: "스타이즈본", director: "브래들리쿠퍼"),

    Song(name: "Counting Start", artist: "비오"),

    Song(name: "V", artist: "박재범")

]

[library인스턴스 설명]

현재는 상속받은 MediaItem유형으로 지정이되어있지만 이 배열의 내용은 반복하는 경우 다시받는 항목은

Movie or Song이 아닌 MediaItem으로 유형이 지정된다.

이를 기본유형으로 사용하려면 아래에 설명된대로 유형을 확인하거나 다른 유형으로 다운캐스트를 해야한다.

# Check Type

 

[사용방법]

is 를 사용하여 인스턴스가 특정 하위 클래스 유형인지 여부를 확인한다.

인스턴스가 하위클래스이면 true, 그렇지 않으면 false를 반환한다.

 

var movieCount = 0

var songCount = 0



for item in library {

    if item is Movie {

        movieCount += 1

        print(item.name)

    } else if item is Song {

        songCount += 1

        print(item.name)

    }

}

print("영화 수: \(movieCount) 노래 수: \(songCount)")

 

[궁금한점]

- 위 반복문에서 item is Movie일경우 item.name을 출력할 수 있지만 director는 출력할 수 없다.

  그 이유는 뭘까 ?

 

 

# DownCasting

[정의]

특정 클래스 유형의 상수 또는 변수는 실제로 배후에서 하위 클래스의 인스턴스를 참조할 수 있다.

 

이것이 사실이라고 생각되는 경우 연산자 as? as!를 사용하여 캐스팅할 수 있다.

- 다운캐스팅이 실패할 수 있으므로 두가지 다른 형식으로 제공된다.

- as?는 다운캐스팅에 성공할 경우 선택적으로 값을 반환하고 아닐경우 nil을 반환

- 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.director의 값을 읽어올 수 없다.

그래서 as?를 지우게되면 director라는 멤버를 가지고있지않다고 컴파일 에러가난다.

 

[다운캐스팅]

상위 클래스인 MediaItem타입으로 초기화되어있는 library는 하위 클래스로 무작정 접근할 수는 없고 값에 접근하려면

다운 캐스팅을 시도하여 접근할 수 있다.

 

library의 item요소는 MediaItem요소이며 값이 Movie타입일 수도있고 Song타입일 수도 있다. 이런경우에는

as?를 사용하여 선택적인 값을 반환한다.

 

 

 

# Type Casting for Any and AnyObject

 

- Any는 함수유형을 포함하여 모든 유형의 인스턴스를 나타낼 수 있다.

- AnyObject는 모든 클래스 유형의 인스턴스를 나타낼 수 있다.

 

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



for thing in things {

    switch thing {

    case 0 as Int:

        print("zero as an Int")

    case 0 as Double:

        print("zero as an 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")

    }

}



let optionalNumbner: Int? = 3

things.append(optionalNumbner)

things.append(optionalNumbner as Any)

print(things[8])