programing

Swift 이니셜라이저가 슈퍼클래스에서 편의 이니셜라이저를 호출할 수 없는 이유는 무엇입니까?

css3 2023. 8. 23. 21:57

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'
    }
}

왜 이것이 허용되지 않는지 모르겠습니다.궁극적으로, 각 클래스의 지정된 이니셜라이저는 필요한 값과 함께 호출되는데, 왜 반복해야 합니까?Binit의 기본값을 지정하여x다시, 형편이 좋을 때.initA괜찮겠습니까?

이것은 스위프트 프로그래밍 가이드에 명시된 "이니셜라이저 체인" 규칙의 규칙 1로, 다음과 같습니다.

규칙 1: 지정된 이니셜라이저는 즉시 수퍼 클래스에서 지정된 이니셜라이저를 호출해야 합니다.

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html

강조해주세요.지정된 이니셜라이저는 편의 이니셜라이저를 호출할 수 없습니다.

규칙과 함께 허용되는 초기화 "방향"을 보여주는 다이어그램이 있습니다.

Initializer Chaining

고려하다

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하층 계급의그런 다음 당신은 지정된 사람에게 전화를 합니다.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(...)하위 클래스에서 초기화를 수행합니다.

이니셜라이저와 그 상속에 대한 자세한 설명은 WWDC-비디오 "403 Intermediate Swift"를 18시 30분에 보십시오.제가 이해한 바와 같이, 다음 사항을 고려해 보십시오.

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를 호출할 수 없고 지정된 전체 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

언급URL : https://stackoverflow.com/questions/24122421/why-cant-swift-initializers-call-convenience-initializers-on-their-superclass