내가 직접 코드로 안치니까
자꾸 까먹어서 확실히 복습하기!
클래스의 상속
class Animal {
var name: String
}
//Bird는 Animal을 상속 받음
class Bird: Animal{
//name
var color: String
}
재정의
- 오버라이딩(overriding)
(영어 뜻: 재정의) 클래스의 상속에서 상위클래스의 속성/메서드를 재정의(기능을 약간 변형하여 사용)하는 것
재정의 규칙
1. 저장 속성 : 재정의 불가
2. 계산 속성 : 확장 방식의 재정의 가능 (실질적 매서드여서)
3. 생성자 : 재정의가 원칙 (원칙상 상속X)
4. 메서드 : 재정의 가능 super.init
==> 속성과 메서드는 재정의 방식이 다름 ⭐️
class Aclass{
var aValue = 1
func doSomething(){
print("hello")
}
}
class Bclass: Aclass{
// 재정의
override func doSomething() {
print("hi")
}
//원래 저장 속성은 재정의 불가하나
// 저장 속성을 계산 속성의 형태로 재정의 가능함
override var aValue: Int{
get {
return 1
}
set {
super.aValue = newValue
}
}
}
초기화
: 저장 속성의 초기값을 설정하여 사용 가능한 상태가 되게하는 인스턴스 생성 과정
초기화 매서드 (=생성자)
: init 으로 명명
- 목적 : 저장 속성에 대한 초기값을 설정하여 사용 가능한 상태가 되게 함
- 인스턴스를 찍어내는 과정
1) 지정 생성자
class Person{
var name: String
var age: Int
//지정 생성자
init(name: String, age: Int){
self.name = name
self.age = age
}
}
2) 편의 생성자
class에서만 사용, 다른 생성자 호출시 필수로 붙여야함!,
편리하게 인스턴스를 찍어낼 수 있음, 내부에서 self.init() 호출, 지정 생성자에 의존함
class Person{
var name: String
var age: Int
init(name: String, age: Int){
self.name = name
self.age = age
}
//편의 생성자
convenience init() {
self.init(name: "홍길동", age: 25)
}
}
상속 관계에서 생성자 위임 규칙 ! ⭐️
[1단계 - 상위 생성자에 대한 고려]
- 상위에 어떤 지정 생성자가 존재하는지?
//🍑 아래 셋 중 하나 택 일
- (상위) 지정 생성자 ===> 1) 하위클래스에서 지정 생성자로 구현 (재정의)
- ===> 2) 하위클래스에서 편의 생성자로 구현 가능 (재정의)
- ===> 3) 구현 안해도됨(반드시 재정의하지 않아도 됨)
- (상위) 편의 생성자 ===> 재정의를 하지 않아도 됨 (호출 불가가 원칙이기 때문에 재정의 제공 안함)
- ===> (만약에 동일한 이름을 구현했다면) 그냥 새로 정의한 것임
[2단계 - (현재단계의) 생성자 구현]
- 1) 지정 생성자 내에서
- ===> (1) 나의 모든 저장 속성을 초기화해야함
- ===> (2) 슈퍼 클래스의 지정 생성자 호출
- 2) 편의 생성자 내에서
- ===> 현재 클래스의 지정생성자 호출 해야함 (편의 생성자를 거치는 것은 상관없음)
(결국 지정 생성자만 모든 저장 속성을 초기화 가능)
class Aclass {
var x = 0
// 기본 생성자가 자동으로 제공됨
// init() {}
}
class Bclass: Aclass {
var y: Int
// 🎾 [1단계] 상위의 지정생성자 고려 ==============================
// 상위에 동일한 이름이 있으므로 재정의 해야함 (이 형태는 안됨)
// init() { }
// (선택 1) 지정생성자로 재정의
override init() { // 상위 클래스와 "이름이 동일한 생성자" 구현은 재정의만 가능함(올바른 재정의) (지정생성자로 구현)
//🍑 현재 단계의 저장 속성 고려
self.y = 0
//🍑 하위 지정 생성자는 반드시 상위 지정 생성자 호출해야함(델리게이트 업)
super.init()
}
// (선택 2) 서브클래스에서 편의생성자로 구현해보기
// 상위 클래스와 "이름이 동일한 생성자" 구현은 재정의만 가능함(올바른 재정의) (지정생성자 필요)
override convenience init() {
// 🍑 편의생성자는 나의 단계에 있는 지정 생성자를 호출해야함(델리게이트 어크로스)
self.init(y: 0)
}
// (선택 3) 재정의 하지 않을 수도 있음 (상속안함)
// 🎾 [2단계] (현재단계의) 생성자 구현 ============================
init(y: Int) {
self.y = y
super.init()
}
}
필수 생성자
: required 키워드가 붙으면 무조거 하위에서 구현해야함
class Aclass {
var x: Int
// 필수 생성자
required init(x: Int) {
self.x = x
}
}
class Bclass: Aclass{
var y: Int
//하위에서 구현!
required init(x: Int) {
self.y = 0
super.init(x: x)
}
}
실패 가능 생성자
실패 가능 -> 실패 불가능 (O)
실패 불가능 -> 실패 가능 (X)
: 실패 불가능한 애가 실패 가능한 것을 호출하는 것이 말이 안되기 때문에 불가능
[ 동일 단계/ 상속 관계에서 호출 ]
내가 실패 가능(?)하면 내로남불
: 실패 가능하던 불가능(?)하던 상관 없음
내가 실패 불가능(?)하면 끼리끼리임
: 실패 불가능(?)만 ok, 실패 가능은 안됨
[ 상속 관계시 재정의 ]
상위 ? 시 하위 실패 불가능 재정의 가능 (강제 언래핑 활용)
: 작은 범위 ⊂ 큰 범위이기 때문
상위 실패 불가능 시 하위 ? 불가능 !
: 큰 범위 ⊄ 작은 범위라서
// 상위 : 생성자 / 하위 : 실패 가능 생성자 예시
class Product {
var name: String
init(name: String) {
//if name.isEmpty { return nil }
self.name = name
}
}
class Item: Product{
var quantity: Int
init?(name: String, quantity: Int){
self.quantity = quantity
super.init(name: name)
}
}
소멸자
: 인스턴스가 메모리에서 제거되기 직전에 자동으로 호출되는 메서드
class Qrcode {
deinit {
print("해당 코드가 소멸됨")
}
}
var a: Qrcode? = Qrcode()
a = nil
오늘 팥 19강까지 복습하려고 했는데
하루종일 팥12함,,,,큰일남