오늘은 스위프트에서의 상속과 타입 캐스팅에 대하여 알아보았다. 개인적인 견해이지만, 스위프트에서는 상속이라는 개념을 그렇게 중요시하지 않는 것 같다. 워낙 스위프트의 꽃인 '프로토콜 및 익스텐션'의 포텐셜이 엄청나서 그런지, 이러한 것들의 사용을 더 권장하는 것 같다. 그리고 개인적으로 재정의를 허용하는 타입 메소드 라는 것을 명시하기 위한 class
키워드가 너무 익숙하지 않다. 몇 번을 다시 봐도 괴이하다 (?)
class 이름: 상속받을 클래스 이름 {
/* 구현부 */
}
final
키워드를 사용하면 재정의 (Override) 방지 가능static
키워드를 사용해 타입 메소드를 만들면 재정의 불가능class
키워드를 사용해 타입 메소드를 만들면 재정의 가능class
앞에 final
을 붙이면 static
키워드를 사용한 것과 동일override
키워드를 사용하여 부모 클래스 메소드 재정의 가능// 기반 클래스 Person
class Person {
var name: String = ""
func selfIntroduce() {
print("저는 \(name)입니다")
}
// final 키워드를 사용하여 재정의를 방지
final func sayHello() {
print("hello")
}
// 타입 메서드
// 재정의 불가 타입 메서드 - static
static func typeMethod() {
print("type method - static")
}
// 재정의 가능 타입 메서드 - class
class func classMethod() {
print("type method - class")
}
// 재정의 가능한 class 메서드라도
// final 키워드를 사용하면 재정의 할 수 없음
// 메서드 앞의 static 과 final class 는 같은 역할
final class func finalCalssMethod() {
print("type method - final class")
}
}
// Person을 상속받는 Student
class Student: Person {
var major: String = ""
override func selfIntroduce() {
print("저는 \(name)이고, 전공은 \(major)입니다")
}
override class func classMethod() {
print("overriden type method - class")
}
// static을 사용한 타입 메서드는 재정의 할 수 없음
// override static func typeMethod() { }
// final 키워드를 사용한 메서드, 프로퍼티는 재정의 할 수 없음
// override func sayHello() { }
// override class func finalClassMethod() { }
}
let yagom: Person = Person()
let hana: Student = Student()
yagom.name = "H43RO"
hana.name = "hana"
hana.major = "Swift"
yagom.selfIntroduce()
// 저는 H43RO입니다
hana.selfIntroduce()
// 저는 hana이고, 전공은 Swift입니다
Person.classMethod()
// type method - class
Person.typeMethod()
// type method - static
Person.finalCalssMethod()
// type method - final class
Student.classMethod()
// overriden type method - class
Student.typeMethod()
// type method - static
Student.finalCalssMethod()
// type method - final class
→ 인스턴스의 타입을 확인하는 용도
→ 클래스의 인스턴스를 부모, 자식 클래스의 타입으로 사용할 수 있는지 확인하는 용도
→ 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("멤버쉽 트레이닝을 갑니다 신남!")
}
}
// 인스턴스 생성
var haero: Person = Person()
var lulu: Student = Student()
var jason: UniversityStudent = UniversityStudent()
→ is
키워드를 통해 타입 확인 가능
var result: Bool
result = haero is Person // true
result = haero is Student // false
result = haero is UniversityStudent // false
result = lulu is Person // true
result = lulu is Student // true
result = lulu is UniversityStudent // false
result = jason is Person // true
result = jason is Student // true
result = jason is UniversityStudent // true
if haero is UniversityStudent {
print("haero은 대학생입니다")
} else if haero is Student {
print("haero은 학생입니다")
} else if haero is Person {
print("haero은 사람입니다")
} // haero은 사람입니다
// 스위프트는 switch 문 케이스 각각에 기본적으로 break 동작을 포함하고 있어
// 먼저 조건에 부합되는 분기에서 switch 문이 실행 종료됨
switch jason {
case is Person:
print("jason은 사람입니다")
case is Student:
print("jason은 학생입니다")
case is UniversityStudent:
print("jason은 대학생입니다")
default:
print("jason은 사람도, 학생도, 대학생도 아닙니다")
} // jason은 사람입니다
switch jason {
case is UniversityStudent:
print("jason은 대학생입니다")
case is Student:
print("jason은 학생입니다")
case is Person:
print("jason은 사람입니다")
default:
print("jason은 사람도, 학생도, 대학생도 아닙니다")
} // jason은 대학생입니다
→ as
를 사용하여 부모 클래스의 인스턴스로 사용할 수 있도록 컴파일러에게 타입 정보를 전환해 줌
→ Any
혹은 AnyObject
로도 타입 정보를 변환할 수 있음
→ 암시적으로 처리되므로 꼭 필요한 경우가 아니라면 생략해도 무방
// UniversityStudent 인스턴스를 생성하여 Person 행세를 할 수 있도록 업 캐스팅
var mike: Person = UniversityStudent() as Person
var jenny: Student = Student()
// var jina: UniversityStudent = Person() as UniversityStudent // 컴파일 오류
// UniversityStudent 인스턴스를 생성하여 Any 행세를 할 수 있도록 업 캐스팅
var jina: Any = Person() // as Any 생략가능
→ as?
또는 as!
를 사용하여 자식 클래스의 인스턴스로 사용할 수 있도록
컴파일러에게 인스턴스의 타입 정보를 전환해줌
as?
를 사용nil
반환하기 때문에 결과 타입은 옵셔널임var optionalCasted: Student?
optionalCasted = mike as? UniversityStudent
optionalCasted = jenny as? UniversityStudent // nil
optionalCasted = jina as? UniversityStudent // nil
optionalCasted = jina as? Student // nil
as!
를 사용var forcedCasted: Student
forcedCasted = mike as! UniversityStudent
//forcedCasted = jenny as! UniversityStudent // 런타임 오류
//forcedCasted = jina as! UniversityStudent // 런타임 오류
//forcedCasted = jina as! Student // 런타임 오류
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: mike as Person) // 멤버쉽 트레이닝을 갑니다 신남!
doSomethingWithSwitch(someone: mike) // 멤버쉽 트레이닝을 갑니다 신남!
doSomethingWithSwitch(someone: jenny) // 등교를 합니다
doSomethingWithSwitch(someone: yagom) // 숨을 쉽니다
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) // 멤버쉽 트레이닝을 갑니다 신남!
doSomething(someone: mike) // 멤버쉽 트레이닝을 갑니다 신남!
doSomething(someone: jenny) // 등교를 합니다
doSomething(someone: yagom) // 숨을 쉽니다