CHAPTER 18 상속
상속은 스위프트의 다른 타입과 클래스를 구별 짓는 클래스만의 특징
다른 클래스로부터 상속을 받지 않은 클래스를 기반클래스(Base class)
__18.1 클래스 상속
__18.2 재정의
부모클래스의 특성을 자식클래스에서 사용하고 싶다면 super 프로퍼티를 사용
super 키워드를 타입 메서드 내에서 사용한다면, 부모클래스의 인스턴스 메서드와 인스턴스 프로퍼티, 서브스크립트에 접근
18.2.1 메서드 재정의
스위프트는 메서드의 반환 타입이나 매개변수가 다르면 서로 다른 메서드로 취급
18.2.2 프로퍼티 재정의
프로퍼티를 재정의할 때는 저장 프로퍼티로 재정의할 수는 없습니다. 프로퍼티를 재정의한다는 것은 프로퍼티 자체가 아니라 프로퍼티의 접근자, 설정자, 프로퍼티 감시자 등을 재정의하는 것을 의미
조상클래스에서 저장 프로퍼티로 정의한 프로퍼티는 물론이고 연산 프로퍼티로 정의한 프로퍼티도 접근자와 설정자를 재정의할 수 있습니다.
프로퍼티를 상속받은 자식클래스에서는 조상클래스의 픞로퍼티 종류(저장, 연산 등)는 알지 못하고 단지 이름과 타입만을 알기 때문
재정의하려는 프로퍼티는 조상클래스 프로퍼티의 이름과 타입이 일치해야 합니다.
조상클래스에서 읽기 전용 프로퍼티였더라도 자식클래스에서 읽고 쓰기가 가능한 프로퍼티로 재정의해줄 수도 있습니다. 그러나, 읽기 쓰기 모두 가능했던 프로퍼티를 읽기 전용으로 재정의해줄 수는 없습니다.
읽기 쓰기가 모두 가능한 프로퍼티를 재정의할 때
접근자와 설정자를 모두 재정의해야 합니다.
18.2.3 프로퍼티 감시자 재정의
상수 저장 프로퍼티나 읽기 전용 연산 프로퍼티는 값을 설정할 수 없으므로 willSet이나 didSet 메서드를 사용한 프로퍼티 감시자를 원천적으로 사용할 수 없기 때문
프로퍼티의 접근자와 프로퍼티 감시자는 동시에 재정의할 수 없습니다.
재정의하는 접근자에 프로퍼티 감시자의 역할을 구현해야 합니다.
18.2.4 서브스크립트 재정의
18.2.5 재정의 방지
부모클래스를 상속받는 자식클래스에서 몇몇 특성을 재정의할 수 없도록 제한하고 싶다면 재정의를 방지하고 싶은 특성 앞에 final 키워드를 명시
클래스를 상속하거나 재정의할 수 없도록 하고 싶다면 class 키워드 앞에 final 키워드를 명시
__18.3 클래스의 이니셜라이저 - 상속과 재정의
값 타입의 이니셜라이저는 이니셜라이저위임을 위해 이니셜라이저끼리 구분할 필요가 없었지만 클래스에서는 지정 이니셜라이저와 편의 이니셜라이저로 역할을 구분
18.3.1 지정 이니셜라이저와 편의 이니셜라이저
지정 이니셜라이저(Designated Initializer)
클래스의 주요 이니셜라이저
필요에 따라 부모클래스의 이니셜라이저를 호출
이니셜라이저가 정의된 클래스의 모든 프로퍼티를 초기화해야 하는 임무
클래스의 이니셜라이저 중 기둥과 같은 역할을 하므로 클래스에 하나 이상 정의
모든 클래스는 하나 이상의 지정 이니셜라이저를 갖습니다.
자손클래스는 지정 이니셜라이저를 갖지 않을 수도 있습니다.
다른 저장 프로퍼티가 없을 가능성이 큽니다.
편의 이니셜라이저(Convenience Initializer)
초기화를 좀더 손쉽게 도와주는 역할
지정 이니셜라이저를 자신 내부에서 호출
편의 이니셜라이저를 사용하면 항상 같은 값으로 초기화가 가능
클래스 설계자의 의도대로 외부에서 사용함]길 원하거나 인스턴스 생성 코드를 작성하는 수고를 덜 때 유용하게 사용
18.3.2 클래스의 초기화 위임
지정 이니셜라이저와 편의 이니셜라이저 사이의 관계
자식 클래스의 지정 이니셜라이저는 부모클래스의 지정 이니셜라이저를 반드시 호출해야 합니다.
편의 이니셜라이저는 자신을 정의한 클래스의 다른 이니셜라이저를 반드시 호출해야 합니다.
편의 이니셜라이저는 궁극적으로는 지정 이니셜라이저를 반드시 호출해야 합니다.
즉,
누군가는 지정 이니셜라이저에게 초기화를 반드시 위임합니다.
편의 이니셜라이저는 초기화를 반드시 누군가에 위임합니다.
18.3.3 2단계 초기화
프로퍼티를 초기화하기 전에 프로퍼티 값에 접근하는 것을 막아 초기화를 안전하게 할 수 있도록 해줍니다. 또, 다른 이니셜라이저가 프로퍼티의 값을 실수로 변경하는 것을 방지
스위프트 컴파일러는 2단계 초기화를 오류 없이 처리하기 위해 다음과 같은 네 가지 안전확인(Safety-checks)을 실행
자식클래스의 지정 이니셜라이저가 부모클래스의 이니셜라이저를 호출하기 전에 자신의 프로퍼티를 모두 초기화했는지 확인합니다.
자식클래스의 지정 이니셜라이저는 상속받은 프로퍼티에 값을 할당하기 전에 반드시 부모클래스의 이니셜라이저를 호출해야합니다.
편의 이니셜라이저는 자신의 클래스에 정의한 프로퍼티를 포함하여 그 어떤 프로퍼티라도 값을 할당하기 전에 다른 이니셜라이저를 호출해야 합니다.
초기화 1단계를 마치기 전까지는 이니셜라이저는 인스턴스 메서드를 호출할 수 없습니다. 또, 인스턴스 프로퍼티의 값을 읽어들일 수도 없습니다. self 프로퍼티를 자신의 인스턴스를 나타내는 값으로 활용할 수도 없습니다.
1단계
클래스에 정의한 각각의 저장 프로퍼티에 초깃값이 할당
클래스가 지정 또는 편의 이니셜라이저를 호출합니다.
그 클래스의 새로운 인스턴스를 위한 메모리가 할당됩니다. 메모리는 아직 초기화되지 않은 상태입니다.
지정 이니셜라이저는 클래스에 정의된 모든 저장 프로퍼티에 값이 있는지 확인합니다. 현재 클래스 부분까지의 저장 프로퍼티를 위한 메모리는 이제 초기화되었습니다.
지정 이니셜라이저는 부모클래스의 이니셜라이저가 같은 동작을 행할 수 있도록 초기화를 양도합니다.
부모클래스는 상속 체인을 따라 최상위 클래스에 도달할 때까지 이 작업을 반복합니다.
최상위 클래스에 도달했을 때, 최상위 클래스까지의 모든 저장 프로퍼티에 값이 있다고 확인하면 해당 인스턴스의 메모리는 모두 초기화된 것입니다. 이로써 1단계가 완료
2단계
저장 프로퍼티들을 사용자정의할 기회
최상위 클래스로부터 최하위 클래스까지 상속 체인을 따라 내려오면서 지정 이니셜라이저들이 인스턴스를 제각각 사용자정의하게 됩니다. 이 단계에서는 self를 통해 프로퍼티 값을 수정할 수 있고, 인스턴스 메서드를 호출하는 등의 작업을 진행할 수 있습니다.
마지막으로 각각의 편의 이니셜라이저를 통해 self를 통한 사용자정의 작업을 진행할 수 있습니다.
18.3.4 이니셜라이저 상속 및 재정의
override 수식어
부모클래스의 편의 이니셜라이저와 동일한 이니셜라이저를 자식클래스에 구현할 때는 override 수식어를 붙이지 않습니다.
자식클래스에서 부모클래스의 편의 이니셜라이저는 절대로 호출할 수 없기 때문
18.3.5 이니셜라이저 자동 상속
자식클래스에서 프로퍼티 기본값을 모두 제공한다고 가정할 때, 다음 두 가지 규칙에 따라 이니셜라이저가 자동으로 상속
규칙1
자식클래스에서 별도의 지정 이니셜라이저를 구현하지 않는다면, 부모클래스의 지정 이니셜라이저가 자동으로 상속됩니다.
규칙2
만약 ‘규칙1’에 따라 자식클래스에서 부모클래스의 지정 이니셜라이저를 자동으로 상속받은 경우 또는 부모클래스의 지정 이니셜라이저를 모두 재정의하여 부모클래스와 동일한 지정 이니셜라이저를 모두 사용할 수 있는 상황이라면 부모클래스의 편의 이니셜라이저가 모두 자동으로 상속됩니다.
18.3.6 요구 이니셜라이저
required 수식어를 클래스의 이니셜라이저 앞에 명시해주면 이 클래스를 상속받은 자식클래스에서 반드시 해당 이니셜라이저를 구현해주어야 합니다.
부모클래스의 일반 이니셜라이저를 자신의 클래스부터 요구 이니셜라이저로 변경할 수도 있습니다. 그럴 때는 required override를 명시해주어 재정의됨과 동시에 요구 이니셜라이저가 될 것임을 명시해주어야 합니다.
참고
야곰의 스위프트 프로그래밍 https://book.naver.com/bookdb/book_detail.nhn?bid=12571019
댓글