상속(Inheriatance)
→ 클래스만 상속이 가능하며 단일 상속만 가능하다!
서브 클래싱(subclassing)
→ 기본 클래스를 기반으로 새로운 클래스를 만드는 작업이다.
상속 받는 클래스 → 서브 클래스
상속 해주는 클래스 → 슈퍼 클래스
예를 통하여 이해해보자. 아래와 같이 Human 클래스가 존재한다.
class Human: Hashable {
var name: String?
var age: Int?
}
그리고, Human 클래스를 상속 받는 Teacher 클래스가 존재한다. Teacher 클래스는 Human 클래스의 멤버들을 모두 가지면서, 추가적으로 더 필요한 멤버들을 가진 클래스이다.
class Teacher: **Human** {
var subject: String?
}
“Teacher이 Human이란 클래스를 상속 받는 것” ⇒ 서브클래싱
- Human → 슈퍼 클래스
- Teacher → 서브 클래스
‼️ 그런데 만약, 상속을 금지하고 싶다면? ⇒ final 을 붙혀준다
. final을 붙혀준다고해서 서브 클래스에서 접근을 못하는 것은 아니다!
오버라이딩(Overriding)
→ 서브 클래스는 슈퍼 클래스의 서브 스크립트, 타입 프로퍼티, 인스턴스 프로퍼티, 타입 메서드, 인스턴스 메서드등을 구현할 수 있는데, 이걸 오버라이딩이라고 한다.
→ override (재정의)라는 키워드를 통하여 구현한다.
메소드 오버라이딩(Method Overriding)
아래의 예를 통하여 한번 이해해보자.
class Human {
func description() {
print("나는 사람입니다")
}
}
class Teacher: Human {
override func description() {
print("나는 선생입니다")
}
}
let miro: Teacher = .init()
miro.description() // "나는 선생입니다"
‼️ 단, 여기서 조심해야될 점은 오버라이딩을 한 경우, Super Class의 메소드를 이미 재정의 해버렸기에 더 이상의 Super Class의 메소드(description())은 실행되지 않는다.
🤔 그렇다면, super class의 메소드도 실행하고, sub class의 메소드도 실행하고 싶다면 어떻게 해야될까?
→ super 를 사용하자!
아래와 같이 서브 클래스에서 오버라이딩을 진행할 때에 슈퍼 클래스의 메소드를 직접 실행해주면 된다.
class Teacher: Human {
override func description() {
super.description()
print("나는 선생입니다")
}
}
let miro: Teacher = .init()
miro.description()
// 나는 사람입니다.
// 나는 선생입니다.
프로퍼티 오버라이딩(Method Overriding)
→ 상속 받은 프로퍼티 값의 변경을 추적할 프로퍼티 옵저버를 추가하거나, 상속 받은 프로퍼티를 오버라이딩을 통하여 해당 속성에 대한 getter, setter를 제공한다.(연산 속성)
→ 프로퍼티 이름 / 타입 을 꼭 명시해주자!
- 저장 프로퍼티의 오버라이딩?..
저장 프로퍼티를 오버라이딩을 할 수는 없을까? → 할 수 없다.
class Human {
var name = "Miro"
}
class Teacher: Human {
override var name: String = "Miro2"// Cannot override with a stored property 'name'
}
그런데, 만약 연산 속성으로 오버라이딩을 한다면?(즉, getter, setter를 모두 구현해주면) → 가능하다!!
class Human {
var name = "Miro"
}
class Teacher: Human {
var alias = "Miro찾기"
override var name: String {
get {
return self.alias
}
set {
self.alias = newValue
}
}
}
- 연산 프로퍼티의 오버라이딩
‼️규칙
- case 1) SuperClass가 get만 구현했다. → SubClass는 get만 구현 OR get,set 둘 다 구현 가능하다
- case 2)SuperClass가 get, set 둘 다 구현했다. → SubClass는 무조건 get, set 둘 다 구현해야된다.
즉, SubClass는 SuperClass 보다 더 할 수는 있지만, 덜 하면 안된다!!
예를 통하여 이해해보자. case 1
class Human {
var name = "Sodeul"
var alias: String {
return self.name + " 바보"
}
}
// get만 구현
class Teacher: Human {
override var alias: String {
return self.name + " 멍청이"
}
}
// get,set 둘 다 구현
class Teacher: Human {
override var alias: String {
get {
return self.name + " 멍청이"
}
set {
self.name = newValue
}
}
}
case 2
class Human {
var name = "Sodeul"
var alias: String {
get {
return self.name + " 바보"
}
set {
self.name = newValue
}
}
}
// **ERROR**
class Teacher: Human {
override var alias: String { // Cannot override mutable property with read-only property 'alias'
return self.name + " 멍청이"
}
}
프로퍼티 옵저버 추가하기
- 저장 프로퍼티 → var로 선언된 프로퍼티만 옵저버를 추가할 수 있다.
- 연산 프로퍼티 → getter/setter 모두 구현된 프로퍼티만 옵저버를 추가할 수 있다.
저장 프로퍼티의 경우
class Human {
var name = "Miro"
}
class Teacher: Human {
override var name: String {
willSet {
print("name 값 변경 된다!!! \(newValue)")
}
didSet {
print("name 값 변경 됐다!!! \(oldValue)")
}
}
}
let teacher: Teacher = .init()
teacher.name = "Unknown"
// name 값이 변경된다!!! Unknown
// name 값이 변경 됐다!!! Miro
💥 Type Casting
- 인스턴스의 Type을 확인
- 인스턴스를 슈퍼 클래스나 하위 클래스로 취급하는 방법
🌟 is , 타입을 체크하는 연산자
표현식 is Type
- 런타임 시에 체크가 일어난다.
- 두 가지 중 하나라도 만족하면 true이다
- 표현식이 Type과 동일하다
- 표현식이 Type의 서브 클래스일 경우
- 나머지는 싹 다 False
예시) 표현식의 Type이 서브 클래스일 경우
class Person { }
class Man: Person { }
let person: Man = .init()
person is Man // true
person is Person // true
🌟 as, 타입 캐스팅을 하는 연산자
표현식 as (변환 할)Type
표현식 as? (변환 할)Type
표현식 as! (변환 할)Type
- 표현식은 변환할 Type으로 캐스팅된 인스턴스를 리턴하게 된다.
- 업 캐스팅과 다운 스캐팅을 통하여 이해해보자.
🫧 Upcasting(업캐스팅)
- 서브 클래스의 인스턴스가 슈퍼 클래스의 타입으로 참조하는 것!
- 업 캐스팅은 항상 성공한다.
- 아래의 예에서 **Man(서브 클래스) as Person(슈퍼 클래스)**를 하는 것이다!
- 아래의 예에서 man은 더 이상 Man class에만 있는 프로퍼티에는 접근할 수 없다.
class Person { }
class Man: Person { }
let man: Man = .init() as Person
🫧 Downcasting(다운 캐스팅)
- 슈퍼 클래스 인스턴스를 서브 클래스의 타입으로 참조하는 것
- 업 캐스팅된 것을 다시 다운 캐스팅할 때에 사용이된다.
- 실패할 수 있기에 as!, **as?**와 같은 연산자를 사용한다.
- as? ⇒ 런타임 시점에서 다운 캐스팅을 하는데, 만약 실패를 하면 nil을 리턴하게 된다.
- as! ⇒ 런타임 시점 에서 다운 캐스팅을 하는데, 실패할 경우 에러를 발생한다.
- 실패를 할 경우
- 만약 Person의 서브 클래스로 Man, Woman이 있다. 근데 person을 Man Class로 만들고, Person으로 업 캐스팅을 한 후, 다운 캐스팅으로 Man class가 아니라, Woman으로 할 경우 실패를 한다.
- 즉, 아래의 예에서 person(원래 Man인데 Person으로 업캐스팅 됨)을 원래대로인 Man으로 다운 캐스팅을 한다.
class Person { }
class Man: Person { }
// Person으로 업 캐스팅하기
let person: Man = .init() as Person
// Man으로 다운 캐스팅하기
guard let man = person as? Man else { return }
📚참고자료
'Swift' 카테고리의 다른 글
[Swift] Error Handling (0) | 2023.02.11 |
---|---|
[Swift] 프로퍼티 옵저버 (0) | 2023.02.11 |
[Swift] Lazy (지연 저장 프로퍼티) (0) | 2023.02.11 |
[Swift] Optional Binding(nil-coalescing) (0) | 2023.02.11 |
[Swift] 고차함수(Map,Filter,Reduce), allSatisfy, forEach,enumerated() (0) | 2023.02.11 |