스위프트의 타입캐스팅
타입 캐스팅은 인스턴스의 타입을 확인하는 용도 이다.
클래스의 인스턴스를 부모 혹은 자식 클래스의 타입으로 사용할 수 있는지 확인하는 용도
is , as 연산자를 사용한다.
정리해서,
인스턴스의 타입을 확인하거나 인스턴스 타입의 슈퍼클래스 또는 서브클래스 타입처럼 다루기 위해 사용!
다음 클래스를 통해 예를 들어서 확인해보려고 한다.
class Person {
var name: String = ""
func breath() {
print("하트 비트")
}
}
// Person 클래스 상속
class Student: Person {
var school: String = ""
func goToSchool() {
print("학교 가자")
}
}
// Student 클래스 상속
class UniversityStudent: Student {
var major: String = ""
func goToMT() {
print("엠티 궈궈~")
}
}
Person 클래스 생성
Person 클래스를 상속받은 Student 클래스 생성
Student 클래스를 상속받은 UniversityStudent 클래스 생성
그리고 각 클래스의 인스턴스를 생성했다.
// 각 클래스 인스턴스 생성
var jak: Person = Person()
var joe: Student = Student()
var jin: UniversityStudent = UniversityStudent()
타입 확인 (is)
is 를 사용해서 타입을 확인할 수 있다.
// 타입 확인 is 사용
var result: Bool
result = jak is Person // true
result = jak is Student // false
result = jak is UniversityStudent // false
result = joe is Person // true
result = joe is Student // true
result = joe is UniversityStudent // false
result = jin is Person // true
result = jin is Student // true
result = jin is UniversityStudent // true
위의 예를 확인해보면
jak 는 Person 클래스의 인스턴스이므로 Person 클래스 타입일 때 true 를 반환한다.
Joe 는 Person -> Student 클래스의 인스턴스이므로 Person 과 Student 클래스 타입일 때 true 를 반환
jin 은 Person -> Student -> UniversityStudent 클래스의 인스턴스 이므로 3개의 클래스 타입에서 true 를 반환하는 것을 확인할 수 있다.
그리고 if 와 switch 에서도 활용해서 사용해볼 수 있다.
// 조건문을 통해서 사용할 수 있다.
// jak 는 Person 클래스 인스턴스
if jak is UniversityStudent {
print("나 대학생!")
} else if jak is Student {
print("나 학생!")
} else if jak is Person {
print("나 사람?!")
}
// switch 문에서도 사용할 수 있다.
// jak 는 Person 클래스 인스턴스
switch jak{
case is Person:
print("사람입니다.")
case is Student:
print("학생입니다.")
case is UniversityStudent:
print("대학생입니다.")
default:
print("아무도 아니야~")
}
// jin 은 University 클래스 인스턴스
switch jin{
case is UniversityStudent:
print("대학생입니다.")
case is Student:
print("학생입니다.")
case is Person:
print("사람입니다.")
default:
print("아무도 아니야~")
}
========== 출력 결과 =========
나 사람?!
사람입니다.
그리고 업 캐스팅과 다운 캐스팅을 통해서 부모 혹은 자식 클래스의 인스턴스로 사용할 수 있도록 타입 정보를 전환해준다.
업 캐스팅 (Up Casting)
as를 사용하여 부모 클래스의 인스턴스로 사용할 수 있도록 해준다.
Any 혹은 AnyObject 로도 타입 정보를 변환할 수 있다.
암시적으로 처리되므로 꼭 필요한 경우가 아니라면 생략해도 무방하다.
// 업 캐스팅
// 부모 클래스의 인스턴스로 사용할 수 있게 해준다.
// 잘 사용하지는 않는다.
var vein: Person = UniversityStudent() as Person
var kaisa: Student = Student()
var caytlin: Any = Person() // as Any 생략 가능
vein 는 UniversityStudent 클래스의 인스턴스를 생성하고 Person 클래스를 사용할 수 있도록 업 캐스팅을 해주었다.
caytlin 은 Person 인스턴스를 생성해서 Any 클래스를 사용할 수 있도록 업 캐스팅 해주었다.
여기서 as Any 는 생략할 수 있다.
다운 캐스팅 (down casting)
as? 또는 as! 를 사용해서 자식 클래스의 인스턴스로 사용할 수 있도록 컴파일러에게 인스턴스의 타입 정보를 전환해준다.
조건부 다운 캐스팅 (as?)
as? 사용
캐스팅에 실패하면, 캐스팅하려는 타입에 부합하지 않는 인스턴스라면 nil 을 반환하기 때문에
결과의 타입은 옵셔널 타입이다.
var vein: Person = UniversityStudent() as Person
var kaisa: Student = Student()
var caytlin: Any = Person() // as Any 생략 가능
// 조건부 다운 캐스팅
// as?
var optionalCasted: Student?
// vein 은 UniversityStudent 클래스 인스턴스
optionalCasted = vein as? UniversityStudent
// kaisa 는 Student 클래스 인스턴스
optionalCasted = kaisa as? UniversityStudent // nil
// caytlin 은 Person 인스턴스
optionalCasted = caytlin as? UniversityStudent // nil
optionalCasted = caytlin as? Student // nil
optionalCasted 는 Student 클래스 옵셔널 타입이다.
optionalCaseted 에 UniversityStudent 클래스의 인스턴스인vein 을 입력받아
UniversityStudent 클래스를 사용할 수 있도록 다운캐스팅 해주었다.
kaisa 는 Student 클래스의 인스턴스이므로 UniversityStudent 클래스로 다운 캐스팅할 수 없기 때문에 nil 을 반환한다.
caytlin 도 마찬가지로 Person 클래스의 인스턴스이므로 다운 캐스팅이 되지 않아 nil 을 반환하는 것을 확인할 수 있다.
강제 다운 캐스팅
as! 사용
캐스팅에 실패하면, 캐스팅하려는 타입에 부합하지 않는 인스턴스라면 런타임 오류가 발생한다.
조건부 다운 캐스팅의 경우에는 nil 을 반환했다.
캐스팅에 성공하면 옵셔널이 아닌 일반 타입을 반환한다.
var vein: Person = UniversityStudent() as Person
var kaisa: Student = Student()
var caytlin: Any = Person() // as Any 생략 가능
// 강제 다운 캐스팅
// as!
var forcedCaseted: Student
forcedCaseted = vein as! UniversityStudent
// 런타임 에러 발생
// forcedCaseted = kaisa as! UniversityStudent
// forcedCaseted = caytlin as! UniversityStudent
// forcedCaseted = caytlin as! Student
vein 은 UniversityStudent 클래스의 인스턴스이므로 다운 캐스팅이 되는 것을 확인할 수 있고
나머지의 경우 다운 캐스팅이 되지 않기 때문에 런타임 오류가 발생한다.
추가적으로 타입 캐스팅을 다양하게 활용해볼 수 있다.
func doSomethingWithSwitch(someone: Person) {
switch someone {
case is UniversityStudent:
(someone as! UniversityStudent).goToMT()
case is Student:
(someone as! Student).goToSchool()
case is Person:
(someone as! Person).breath()
}
}
doSomethingWithSwitch(someone: vein as Person)
doSomethingWithSwitch(someone: vein)
doSomethingWithSwitch(someone: kaisa)
doSomethingWithSwitch(someone: jak)
========== 출력 결과 =========
엠티 궈궈~
엠티 궈궈~
학교 가자
하트 비트
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: vein as Person)
doSomething(someone: vein)
doSomething(someone: kaisa)
doSomething(someone: jak)
========== 출력 결과 ==========
엠티 궈궈~
엠티 궈궈~
학교 가자
하트 비트
- 참고 사이트 -
www.edwith.org/boostcamp_ios/lecture/11312
minsone.github.io/mac/ios/swift-type-casting-summary
'iOS > Swift' 카테고리의 다른 글
[Swift] 23. assert / guard (0) | 2020.11.29 |
---|---|
스위프트는 어떻게 동작할까? (0) | 2020.11.25 |
[Swift] 21. 옵셔널 체이닝과 nil 병합 (0) | 2020.11.18 |
[Swift] 20. 인스턴스 생성 및 소멸 (init / deinit) (0) | 2020.11.11 |
[Swift] 19. 상속(Inheritance) (0) | 2020.11.09 |