일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 프로그래머스 최댓값 만들기(2)
- 프로그래머스 암호 해독
- 객체지향
- swift
- cocoapods 설치 오류
- 프로그래머스 조건에 맞게 수열 변경하기 3
- 조건에 맞게 수열 변경하기 3
- 스파르타코딩캠프
- 스파르타 코딩클럽 내일배움캠프
- 프로그래머스 문자열 정렬하기 (1)
- ruby설치
- 문자열 정렬하기 (1)
- continue
- Error installing cocoapods
- 프로그래머스 배열 만들기1
- 연산자
- 프로그래머스 n의 배수 고르기
- 문자열 붙여서 출력하기
- array
- Til
- 프로그래머스 자동커밋
- 프로그래머스 n번째 원소까지
- n번째 원소까지
- 프로그래머스
- Break
- 프로그래머스 주사위 게임1
- 배열 만들기1
- 프로그래머스 문자열 붙여서 출력하기
- 주사위 게임1
- 스페인어
- Today
- Total
dev._.note
[Swift] 타입 캐스팅(Type Casting) 본문
📌 타입 캐스팅(Type Casting)
인스턴스의 타입을 확인하거나, 해당 인스턴스를 자신의 클래스 계층에 있는 상위 혹은 하위 클래스로 처리하는 방법
- 타입 캐스팅은 is 와 as 연산자로 구현.
- 이 두 연산자는 값의 타입을 확인하거나 값을 다른 타입으로 지정.
- 단순하면서도 보고 이해하기 쉬운 표현 방식.
- 해당 타입이 프로토콜을 따르는지(Protocol Conformance)도 확인가능.
타입 캐스팅 연산자 4종류
expression is type
expression as type
expression as? type
expression as! type
- is 연산자는 런타임에 expression 이 특정 type 으로 캐스팅 되는지 체크. bool타입 return.
- as 연산자는 컴파일 단계에서 캐스팅이 실행. 언제나 특정 type 으로 캐스팅이 성공할 때만 사용이 가능. 업캐스팅(Upcasting) 혹은 브릿징(Bridging) 에 사용.
- as? 연산자는 런타임에 캐스팅하여 특정 type 의 옵셔널을 반환. 성공하면 옵셔널 값을 반환하고 실패하면 nil 을 반환.
- as! 연산자는 런타임에 특정 type 으로 강제 캐스팅. 캐스팅에 실패할 경우 런타임 에러가 발생할 수 있으므로 사용권장 안함.
업캐스팅(Upcasting): 해당 타입의 상위 타입의 인스턴스로 캐스팅
브릿징(Bridging): NSString 과 같은 Foundation 타입을 String 과 같은 스위프트 표준 라이브러리로 캐스팅
타입 체크와 다운캐스팅 (Checking Type & Downcasting)
타입 캐스팅을 위해 클래스 계층 예시를 만들어 보겠습니다.
먼저, 가장 상위 클래스인 MediaItem 을 정의.
class MediaItem {
var name: String
init(name: String) {
self.name = name
}
}
다음 MediaItem 클래스를 상속받는 Movie 와 Song 클래스 두 개를 선언.
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)
}
}
생성자는 MediaItem 클래스를 상속받기 때문에 공통적으로 name 을 받아 초기화하며 Movie 클래스의 경우 추가적으로 director 를 받아 초기화하고 Song 클래스의 경우 artist 를 받아 초기화.
마지막으로, 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]
스위프트의 타입 체커는 Movie 와 Song 이 공통적으로 MediaItem 을 부모클래스로 가지는 것을 알고 library 의 타입을 [MediaItem] 으로 추론함. 그렇기 때문에 실제로 해당 배열에서 값을 꺼내서 쓸 때는 MediaItem으로 추출이 되기 때문에 Movie나 Song으로 사용하려면 다운캐스팅을 해주어야 함.
is 연산자로 타입 체크하기
타입 체크를 할 때는 is 연산자를 활용하면 인스턴스가 특정 하위 클래스 타입인지 확인.
인스턴스가 하위 클래스 유형이면 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"
library 배열에는 Movie 인스턴스는 2개, Song 인스턴스는 3개가 들어있는 것을 확인가능.
as 연산자로 다운캐스팅 하기
특정 클래스 타입의 상수나 변수가 실제로는 해당 인스턴스의 하위클래스를 나타내고 있을 수 있음.
이 때 as? 나 as! 연산자를 사용하여 하위 클래스로 다운캐스팅하여 하위클래스로 해당 인스턴스를 사용가능.
다운캐스팅은 실패할 수도 있기때문에, 두 가지 연산자가 있음.
as? 의 경우 옵셔널 값을 반환.
as! 의 경우 강제 추출(force-unwrap)한 값을 반환.
- 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
as? 연산자를 이용하여 다운캐스팅 하고 반환된 옵셔널 값을 if-let 구문으로 처리하는 방법. 다운캐스팅 하는 가장 일반적인 방법.
캐스팅은 실제로 인스턴스를 수정하거나 그 값을 변경하지 않음. 단순히 캐스팅 된 타입으로 해당 인스턴스를 처리하고 접근.
Any나 AnyObject를 타입 캐스팅 하는 방법
스위프트는 불특정한 타입을 다루기 위해 두 가지 특별한 타입을 제공.
- 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)" })
things 배열에서 특정 타입의 값을 찾아내기 위해서는 is 나 as 를 이용한 switch 문을 이용.
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 타입은 옵셔널 타입을 포함한 모든 타입을 나타낼 수 있음. 값 타입이 Any 타입으로 기대되는 곳에서 만약 옵셔널 값을 사용한다면 스위프트는 warning 을 나타냄. 이 때는 아래 처럼 as 연산자를 사용하여 옵셔널 타입을 Any 로 명시적 캐스팅하여 사용하면 warning 은 사라짐.
let optionalNumber: Int? = 3
things.append(optionalNumber) // Warning
things.append(optionalNumber as Any) // No warning
정리
- is 나 as 연산자를 이용하여 타입 캐스팅을 할 수 있다.
- is 연산자를 이용하여 타입 체크를 할 수 있다.
- 다운캐스팅을 할 때는 as? 나 as! 연산자를 이용할 수 있다.
'Dev > SWIFT' 카테고리의 다른 글
[Swift] 키오스크 과제 (1) | 2023.12.07 |
---|---|
[Swift] 접근 제한자 (0) | 2023.12.06 |
[Swift] didSet 과 willSet (0) | 2023.12.04 |
[Swift] readLine() (2) | 2023.12.02 |
[Swift] 계산기 만들기 (0) | 2023.12.01 |