두 가지 클래스를 고려하십시오.
class A {
var x: Int
init(x: Int) {
self.x = x
}
convenience init() {
self.init(x: 0)
}
}
class B: A {
init() {
super.init() // Error: Must call a designated initializer of the superclass 'A'
}
}
왜 이것이 허용되지 않는지 모르겠습니다. 궁극적으로 각 클래스의 지정된 이니셜 라이저는 필요한 값으로 호출됩니다. 그래서 의 편의 가 잘 작동 할 때 기본값을 다시 지정하여 B
‘s 에서 자신을 반복해야하는 이유는 무엇입니까?init
x
init
A
답변
이것은 Swift Programming Guide에 명시된 “Initializer Chaining”규칙의 규칙 1입니다.
규칙 1 : 지정된 이니셜 라이저는 직계 수퍼 클래스에서 지정된 이니셜 라이저를 호출해야합니다 .
내 강조. 지정된 이니셜 라이저는 편의 이니셜 라이저를 호출 할 수 없습니다.
이니셜 라이저 “방향”이 허용되는 규칙을 보여주는 다이어그램이 있습니다.
답변
중히 여기다
class A
{
var a: Int
var b: Int
init (a: Int, b: Int) {
print("Entering A.init(a,b)")
self.a = a; self.b = b
}
convenience init(a: Int) {
print("Entering A.init(a)")
self.init(a: a, b: 0)
}
convenience init() {
print("Entering A.init()")
self.init(a:0)
}
}
class B : A
{
var c: Int
override init(a: Int, b: Int)
{
print("Entering B.init(a,b)")
self.c = 0; super.init(a: a, b: b)
}
}
var b = B()
클래스 A의 모든 지정된 이니셜 라이저가 재정의되기 때문에 클래스 B는 A의 모든 편의 이니셜 라이저를 상속합니다. 따라서이를 실행하면
Entering A.init()
Entering A.init(a:)
Entering B.init(a:,b:)
Entering A.init(a:,b:)
이제 지정된 이니셜 라이저 B.init (a : b :)가 기본 클래스 편의 이니셜 라이저 A.init (a :)를 호출하도록 허용하면 B.init (a :, b :)에 대한 재귀 호출이 발생합니다. ).
답변
무한 재귀로 끝날 수 있기 때문입니다. 중히 여기다:
class SuperClass {
init() {
}
convenience init(value: Int) {
// calls init() of the current class
// so init() for SubClass if the instance
// is a SubClass
self.init()
}
}
class SubClass : SuperClass {
override init() {
super.init(value: 10)
}
}
그리고보세요 :
let a = SubClass()
어느 전화 SubClass.init()
가 전화 SuperClass.init(value:)
할 것 SubClass.init()
입니다.
지정 / 편의 초기화 규칙은 클래스 초기화가 항상 정확하도록 설계되었습니다.
답변
이에 대한 해결 방법을 찾았습니다. 매우 예쁘지는 않지만 수퍼 클래스의 값을 모르거나 기본값을 설정하려는 문제를 해결합니다.
당신이해야 할 일은 init
바로 init
서브 클래스 에서 편리함을 사용하여 슈퍼 클래스의 인스턴스를 만드는 것입니다 . 그런 다음 init
방금 만든 인스턴스를 사용하여 지정된 수퍼를 호출합니다 .
class A {
var x: Int
init(x: Int) {
self.x = x
}
convenience init() {
self.init(x: 0)
}
}
class B: A {
init() {
// calls A's convenience init, gets instance of A with default x value
let intermediate = A()
super.init(x: intermediate.x)
}
}
답변
편리한 초기화 코드를 init()
새로운 도우미 함수로 추출하고 하위 클래스에서 초기화를 수행하도록 foo()
호출 foo(...)
하십시오.
답변
이니셜 라이저와 그 상속에 대한 자세한 설명은 18:30에 WWDC 비디오 “403 intermediate Swift”를 참조하십시오. 내가 이해했듯이 다음을 고려하십시오.
class Dragon {
var legs: Int
var isFlying: Bool
init(legs: Int, isFlying: Bool) {
self.legs = legs
self.isFlying = isFlying
}
convenience initWyvern() {
self.init(legs: 2, isFlying: true)
}
}
하지만 이제 Wyrm 하위 직업을 생각해보십시오. Wyrm은 다리도 날개도없는 용입니다. 따라서 와이번의 이니셜 라이저 (2 개 다리, 2 개 날개)가 잘못되었습니다! 편리한 Wyvern-Initializer를 단순히 호출 할 수없고 지정된 전체 초기화 프로그램 만 호출하면이 오류를 피할 수 있습니다.
class Wyrm: Dragon {
init() {
super.init(legs: 0, isFlying: false)
}
}
답변
왜 당신은 두 개의 이니셜 라이저를 가지고 있지 않습니까? 하나는 기본값을 가지고 있습니까?
class A {
var x: Int
init(x: Int) {
self.x = x
}
init() {
self.x = 0
}
}
class B: A {
override init() {
super.init()
// Do something else
}
}
let s = B()
s.x // 0