기존 답변은 이야기의 절반 만 알려줍니다 convenience
. 이야기의 나머지 절반, 기존 답변 중 어느 것도 다루지 않는 절반은 의견에 Desmond가 게시 한 질문에 대답합니다.
왜 스위프트 convenience
가 호출해야하기 때문에 초기화 프로그램 앞에 강제로 배치 해야 self.init
합니까?`
나는 약간 그것에 감동 이 대답 I 커버하는, 몇 가지 세부 사항에 스위프트의 초기화 규칙, 그러나 주요 초점은 거기에 있었다 required
단어. 그러나 그 대답은 여전히이 질문 과이 대답과 관련된 것을 다루고있었습니다. Swift 이니셜 라이저 상속이 어떻게 작동하는지 이해해야합니다.
Swift는 초기화되지 않은 변수를 허용하지 않기 때문에 상속받은 클래스에서 모든 (또는) 초기화를 상속받을 수는 없습니다. 초기화되지 않은 인스턴스 변수를 서브 클래스로 서브 클래스하고 추가하면 이니셜 라이저 상속이 중지됩니다. 그리고 우리 자신의 이니셜 라이저를 추가 할 때까지 컴파일러는 우리에게 소리 칠 것입니다.
분명히 초기화되지 않은 인스턴스 변수는 기본값이 제공되지 않은 인스턴스 변수입니다 (옵션 및 암시 적으로 래핑되지 않은 옵션은 기본값을 자동으로 가정합니다 nil
).
따라서이 경우 :
class Foo {
var a: Int
}
a
초기화되지 않은 인스턴스 변수입니다. a
기본값을 지정 하지 않으면 컴파일되지 않습니다 .
class Foo {
var a: Int = 0
}
또는 이니셜 a
라이저 메소드에서 초기화하십시오.
class Foo {
var a: Int
init(a: Int) {
self.a = a
}
}
자, 만약 우리가 서브 클래스 Foo
라면 어떻게 될까요?
class Bar: Foo {
var b: Int
init(a: Int, b: Int) {
self.b = b
super.init(a: a)
}
}
권리? 변수를 추가하고 초기화 할 값을 설정하여 b
컴파일되도록 초기화 도구를 추가했습니다 . 어떤 언어를 사용 하느냐에 따라 Bar
상속 된 Foo
이니셜 라이저 인 것으로 예상 할 수 있습니다 init(a: Int)
. 그러나 그렇지 않습니다. 그리고 어떻게 할 수 있습니까? 어떻게 Foo
'의 init(a: Int)
노하우는 방법에 값 할당하는 b
것을 변수 Bar
추가를? 그렇지 않습니다. 따라서 Bar
모든 값을 초기화 할 수없는 이니셜 라이저로 인스턴스를 초기화 할 수 없습니다.
이것과 어떤 관련이 convenience
있습니까?
이니셜 라이저 상속 에 대한 규칙을 살펴 보자 .
규칙 1
서브 클래스가 지정된 이니셜 라이저를 정의하지 않으면 모든 수퍼 클래스 지정 이니셜 라이저를 자동으로 상속합니다.
규칙 2
서브 클래스가 규칙 1에 따라 상속 받거나 정의의 일부로 사용자 정의 구현을 제공하여 모든 수퍼 클래스 지정 이니셜 라이저의 구현을 제공하는 경우 모든 수퍼 클래스 편의 이니셜 라이저를 자동으로 상속합니다.
편의 초기화에 대해 언급 한 규칙 2에 주목하십시오.
뭐라고 그래서 convenience
키워드가 수행 할 IS는 초기화가되는 우리에게 표시 상속 될 수 있습니다 서브 클래스가 디폴트 값없이 추가 인스턴스 변수.
이 예제 Base
클래스를 보자 .
class Base {
let a: Int
let b: Int
init(a: Int, b: Int) {
self.a = a
self.b = b
}
convenience init() {
self.init(a: 0, b: 0)
}
convenience init(a: Int) {
self.init(a: a, b: 0)
}
convenience init(b: Int) {
self.init(a: 0, b: b)
}
}
convenience
여기에 이니셜 라이저 가 3 개 있습니다. 그것은 상속받을 수있는 세 개의 이니셜 라이저가 있다는 것을 의미합니다. 그리고 우리는 하나의 지정된 이니셜 라이저를 가지고 있습니다 (지정된 이니셜 라이저는 편의 이니셜 라이저가 아닌 모든 이니셜 라이저입니다).
기본 클래스의 인스턴스를 네 가지 방법으로 인스턴스화 할 수 있습니다.
자, 서브 클래스를 만들어 봅시다.
class NonInheritor: Base {
let c: Int
init(a: Int, b: Int, c: Int) {
self.c = c
super.init(a: a, b: b)
}
}
에서 상속받습니다 Base
. 우리는 우리 자신의 인스턴스 변수를 추가했고 기본값을주지 않았으므로 우리 자신의 초기화자를 추가해야합니다. 우리는 하나를 추가 init(a: Int, b: Int, c: Int)
했지만 Base
클래스의 지정된 초기화 프로그램의 서명과 일치하지 않습니다 init(a: Int, b: Int)
. 즉, 우리는 다음 에서 이니셜 라이저를 상속 하지 않습니다 Base
.
그래서 우리가에서 상속 받으면 어떤 일이 일어날 까요? Base
그러나 우리는 계속해서 지정된 이니셜 라이저와 일치하는 이니셜 라이저를 구현했습니다 Base
.
class Inheritor: Base {
let c: Int
init(a: Int, b: Int, c: Int) {
self.c = c
super.init(a: a, b: b)
}
convenience override init(a: Int, b: Int) {
self.init(a: a, b: b, c: 0)
}
}
이제이 클래스에서 직접 구현 한 두 개의 이니셜 라이저 외에 Base
클래스의 지정된 이니셜 라이저와 일치하는 이니셜 라이저를 구현했기 때문에 모든 Base
클래스의 convenience
이니셜 라이저 를 상속합니다 .
일치하는 서명을 가진 이니셜 라이저가 convenience
여기에 차이가 없음을 표시 합니다. Inheritor
지정된 초기화 프로그램이 하나만 있음을 의미합니다 . 따라서에서 상속받은 경우 Inheritor
하나의 지정된 이니셜 라이저를 구현 한 다음 Inheritor
편의 이니셜 라이저를 상속 하면 모든 Base
지정된 이니셜 라이저를 구현하고 해당 convenience
이니셜 라이저를 상속 할 수 있습니다 .