본문 바로가기
etc/Swift

타입 캐스팅(Type Casting)

by IT learning 2021. 5. 28.
728x90

 

오늘은 타입 캐스팅에 대해 공부하였다.

 

본래의 타입 캐스팅이란 이런거였다.

 let someInt: Int = 100
 let someDouble: Double = Double(someInt)

이러느낌으로 int 형의 인스턴스를 Double로 바꾸던가 뭐 그러한 방법.

근데 스위프트에서는 이런 행위를 타입 캐스팅이라고 부르지 않는다. 얘는 따로 Double 형을 하나 더 생성한 느낌이다. 아무튼 완전히 다르다.

 

스위프트에서의 타입 캐스팅이란, 인스턴스의 타입을 확인하는 용도이다. 또는 클래스의 인스턴스를 부모 혹은 자식 클래스의 타입으로 사용할 수 있는지 확인하는 용도로 쓰인다. 말 그대로 그냥 확인해주는 도구이다.

 

키워드는 is, as 를 사용한다.

 

클래스 만들기

class Person {
    var name: String = ""
    func breath() {
        print("숨을 쉽니다")
    }
}

class Student: Person {
    var school: String = ""
    func goToSchool() {
        print("등교를 합니다")
    }
}

class UniversityStudent: Student {
    var major: String = ""
    func goToMT() {
        print("MT를 갑니다")
    }
}

var it: Person = Person()
var hana: Student = Student()
var jason: UniversityStudent = UniversityStudent()

일단 타입 캐스팅을 확인하기 위해 클래스들을 만들었다.

 

타입 확인

var result: Bool

result = it is Person // true
result = it is Student // false
result = it is UniversityStudent // false

result = hana is Person // true
result = hana is Student // true
result = hana is UniversityStudent // false

result = jason is Person // true
result = jason is Student // true
result = jason is UniversityStudent // true

방금 위에서 만든 인스턴스들을 가지고 이것이 사람인지, 학생인지, 대학생인지를 구분할 수 있게 해주는게 타입 캐스팅이다.

그리고 상속을 받은 것들은 부모 클래스를 가져다 놔도 True로 나온다.

if it is UniversityStudent {
    print("it 는 대학생입니다")
} else if it is Student {
    print("it 는 학생입니다")
} else {
    print("it는 사람입니다")
} // it는 사람입니다


switch jason {
case is Person:
    print("사람입니다")
case is Student:
    print("학생입니다")
case is UniversityStudent:
    print("대학생입니다")
default:
    print("걍 아무것도 아닙니다")
} // 사람입니다


switch jason {
case is UniversityStudent:
    print("대학생입니다")
case is Student:
    print("학생입니다")
case is Person:
    print("사람입니다")
default:
    print("걍 아무것도 아닙니다")
} // 대학생입니다

이렇게 if 문으로 원하는 대답을 들을수도 있고, switch 문으로도 작성할 수가 있다. 여기서 유의할 점이 하나 있다.

switch문에서 첫번째 스위치 문에서는 사람이 첫번째 케이스로 되어있고, 두번째 스위치 문에서는 대학생이 첫번째 케이스로 되어있다.

뭐가 먼저인지에 따라서 값이 바뀐다. 상속이 되어있으니까 일단 먼저 보이는 것부터 들어가고 끝낸다. 이 점 유의하자.

 

업 캐스팅

var mike: Person = UniversityStudent() as Person
var jenny: Student = Student()
// var jina: UniversityStudent = Person() as UniversityStudent // 컴파일 오류
var jina: Any = Person() // as Any 생략가능

업캐스팅은 as를 사용해서 부모클래스의 인스턴스로 활용할 수 있도록 컴파일러에게 타입정보를 전환해준다.

Any 혹은 AnyObject로도 타입정보를 변환할 수 있다.

코드를 보자. mike 라는 애 한테 사람이라는 클래스를 넣고 싶어 한다. 근데 대학생 클래스 가져와서 '너 사람으로 바꿔 ㅇㅇ' 이렇게 해서 사람으로 주입 시켰다. 상속 관계이기에 업 캐스팅이 가능하다

주석 처리된 코드는 업 캐스팅이 아니라 부모에게서 자식 나와라 하는 말이라 당연히 컴파일 오류가 발생한다.

마지막 코드는 Any로 설정해놓아서 원하는 클래스를 가져다가 써도 상관없다. 그리고 뒤에 as Any 가 생략 가능하다.

 

다운 캐스팅

다운 캐스팅은 자식 클래스의 인스턴스로 사용할 수 있도록 컴파일러에게 인스턴스의 타입정보를 전환해준다.

다운 캐스팅은 2가지 조건이 있다. 같이 보자.

 

조건부 다운 캐스팅

var optionalCasted: Student?

optionalCasted = mike as? UniversityStudent
optionalCasted = jenny as? UniversityStudent // nil
optionalCasted = jina as? UniversityStudent // nil
optionalCasted = jina as? Student // nil

이렇게 '바꿔도 괜찮을까? 바꿔줄께.." 뭐 이런 느낌이다. 그래서 맞지 않는 것들은 자연스레  nil 이 나오게 된다.

 

강제 다운 캐스팅

optionalCasted = mike as! UniversityStudent
//optionalCasted = jenny as! UniversityStudent 런타임 오류
//optionalCasted = jina as! UniversityStudent  런타임 오류
//optionalCasted = jina as! Student            런타임 오류

얘는 좀 많이 다르다. 그냥 "니 이제부터 이거 해, 하라면 해!" 라는 느낌이다. 그래서 먹질 못한다. 컴파일러가 고통받는다.

 

활용

func doSomething(someone: Person) {
    if let universityStudent = someone as? UniversityStudent {
        universityStudent.goToMT()
    } else if let student = someone as? Student {
        student.goToSchool()
    } else if let person = someone as? Person {
        person.breath()
    }
}


doSomething(someone: mike as Person)
// MT를 갑니다

doSomething(someone: mike)
// MT를 갑니다

doSomething(someone: jenny)
// 등교를 합니다

doSomething(someone: it)
// 숨을 쉽니다

타입 캐스팅을 활용하는 코드이다. 이 코드는 원하는 someone을 넣어주면, 함수에서 기준에 맞는 것으로 들어가게 된다.

as? 조건부 타입 캐스팅을 사용하여 맞으면 들어가고 아니면 말고를 보여준다.

728x90

'etc > Swift' 카테고리의 다른 글

프로토콜(Protocol)  (0) 2021.05.28
assert와 guard  (0) 2021.05.28
옵셔널 체이닝(부제 - 갈고리 살인마)  (0) 2021.05.28
인스턴스 생성과 소멸  (0) 2021.05.28
상속  (0) 2021.05.28

댓글

IT_learning's Commit