Swift 이니셜 라이저가 수퍼 클래스에서 편의 이니셜 라이저를 호출 할 수없는 이유는 무엇입니까?
두 가지 클래스를 고려하십시오.
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 에서 자신을 반복해야하는 이유는 무엇입니까?initxinitA
이것은 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()입니다.
지정 / 편의 초기화 규칙은 클래스 초기화가 항상 정확하도록 설계되었습니다.
I found a work around for this. It's not super pretty, but it solves the problem of not knowing a superclass's values or wanting to set default values.
All you have to do is create an instance of the superclass, using the convenience init, right in the init of the subclass. Then you call the designated init of the super using the instance you just created.
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)
}
}
Consider extracting the initialization code from your convenient init() to a new helper function foo(), call foo(...) to do the initialization in your sub-class.
Look at the WWDC-video "403 intermediate Swift" at 18:30 for an in depth explanation of initializers and their inheritance. As I understood it, consider the following:
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
'Programing' 카테고리의 다른 글
| 직관 론적 유형 이론과 동등한 조합 논리는 무엇입니까? (0) | 2020.09.15 |
|---|---|
| DELETE 요청 본문에 대한 RESTful 대안 (0) | 2020.09.15 |
| 프로그래밍 방식으로 Android 애플리케이션을 '다시 시작'하는 방법 (0) | 2020.09.15 |
| Mac에서 Parallels Windows localhost에 액세스 (0) | 2020.09.15 |
| 이 GLSL rand () 원 라이너의 기원은 무엇입니까? (0) | 2020.09.15 |