2017-11-21 27 views
4

다음은 놀이터에서 가져온 샘플 코드입니다. 내가 이해하지 못하는 이유는 하위 클래스의 b 변수가 var 유형이어야하고 let이 될 수 없기 때문입니다. 누군가 나를 이해하도록 도와 줄 수 있습니까?파생 클래스의 편의 초기화 프로그램에서 상수 속성을 초기화 할 수 없습니다.

class Base1 { 
    init() { } 
} 

class Sub1: Base1 { 
    let b: Int 

    override init() { 
     super.init() 
    } 

    convenience init(b: Int) { 
     self.b = b // Cannot assign to property: 'b' is a 'let' constant 
     self.init() 
    } 
} 
+0

단지 : @Martin R 다른 지정 초기화를 작성하고 기본값을 제공하기 위해, 오버라이드 (override) 초기화하기 전에 편의를 위해 사용하는, 의견 중 하나에 제안

class Sub1: Base1 { var b: Int? override init() { super.init() } convenience init(b: Int) { self.init() self.b = b } } 

아니면 더 좋은 방법이며, 문서 저장 프로퍼티에 따라 override init() 대신에'init (b : Int)'에서'편의성'을 사용하는 실수가 하나있었습니다. –

답변

2

나는 하위 클래스 작성과 클래스 초기화 자와 더 관련이 없다고 생각합니다.

이 오류는이 클래스와 다른 문제를 보여줄 것 letvar까지 b을 변경, 절반 이야기 :

  • 이니셜 라이저는 클래스의 각 저장 속성에 대한 초기 값을 설정해야합니다. init을 무시하면 b의 기본값을 제공해야합니다.

  • 편리한 이니셜이 그것의 (a let 상수로 b을 유지하는 방법에 대한 의견에서 제시 한 개선을위한 마틴 R 덕분에) 모습입니다 self

에 액세스하기 전에 지정된 초기화를 호출해야합니다 :

class Base1 { 
    init() { } 
} 

class Sub1: Base1 { 
    let b: Int 

    convenience override init() { 
     self.init(b: 5) 
    } 

    init(b: Int) { 
     self.b = b 
     super.init() 
    } 
} 

let one = Sub1(b: 10) 
one.b // prints 10 
let two = Sub1() 
two.b // prints 5 
+4

Better :'init (b : Int)','init()'는'self.init (b : 5)'를 호출하는 편의 초기화 프로그램을 제공한다. - 그러면 b를 상수로 유지할 수 있습니다. –

+0

그게 훨씬 낫 네. 네가 대답의 일부로 추가하고 싶은거야, 아니면 내가 편집 할까? – paulvs

+1

자유롭게 편집 할 수 있습니다! –

1

우선, imho는 파생 된 클래스가 없으므로 하위 클래 싱을 제거하고 비슷한 오류가 발생할 수 있습니다.

두 번째로, 편의 초기화 프로그램의 "특성"과 그 사용법 때문이라고 생각합니다. 그것들은 "선택적인"(사용법에서) 이니셜 라이저로서, 예를 들어 어떤 복잡한 데이터 (다른 클래스 나 구조체와 같은)로부터 초기화하기위한 지름길을 제공하기위한 것이다.

b를 초기화해야합니다 init을 지정된대로 따라서
class Sub1: Base1 { 
    let b: Int 

    // You must init b 
    // Or ger error: property 'self.b' not initialized ... 
    init(b: Int) { 
     self.b = b 
     super.init() 
    } 

    // Do you really need the code below now? 
    //convenience init(b: Int) { 
    // self.b = b 
    // self.init() 
    //} 
} 

, 편의 : 어쨌든 필요가 지정된 초기화b를 초기화하는 것처럼, 도움이 아무것도 가져 오지 것이다 샘플 편의 초기화에 self.b의 초기화를 추가 당신이 쓴대로 이니셜 라이저는 무의미 해집니다.

세 번째로 이 허용된다고 가정합니다. 따라서 편의 초기화 프로그램이 반드시 지정된 하나를 호출하지 않고 위임됩니다.

... 

convenience init(b: Int) { 
    self.b = b 
    self.init(c: 10) 
} 

// later some crazy guy adds his own "convenience" initializer and points your to this one. 
convenience init(c: Int) { 
    self.c = c 
    if c == 7 { 
     self.b = 11 
    } 
    self.init() 
} 

지금 당신은 "컴파일러"이며 일정 b이이 일정 값과 무엇 값입니다으로 설정된다 말해 상상 : 따라서 그런 일을 할 수 있을까요?

마지막으로, 나의 이해에 올바른 사용은 그렇게 될 수있다 :

class Base1 { 
    init() {} 
} 


class Sub1: Base1 { 
    let b: Int 

    init(b: Int) { 
     self.b = b 
     super.init() 
    } 

    // Convenience initializer providing default value 
    override convenience init() { 
     self.init(b: 7) 
    } 
} 

그래서, 내 관심사는 당신이 정말 편리 초기화에서 초기화 let b 수 있도록함으로써 달성하기 위해 원하는 것을 명확하게 이해하지 않는다는 것입니다?

+0

실제로는 사용자 정의 매개 변수의 기본값을 가질 수 있으므로 사용자 정의 초기화 프로그램이 필요하지 않지만 사용자는 완전합니다. – Sulthan

1

스위프트에서 지정된 초기화 프로그램을 사용하여 모든 저장된 속성을 설정합니다. 이것은 공식에서입니다 documentation :

지정된 초기화 프로그램은 클래스의 기본 이니셜 라이저입니다. 지정된 초기화 프로그램은 에 의해 소개 된 모든 속성을 완전히 초기화하고 적절한 수퍼 클래스 이니셜 라이저를 호출하여 수퍼 클래스 체인 위로 초기화 프로세스를 계속 진행합니다.

편의 초기화는 2 차이므로 desginated initializer를 호출해야합니다.

또한 특정 유스 케이스 또는 입력 값 유형에 대한 클래스 인 의 인스턴스를 생성하는 편의 초기화 프로그램을 정의 할 수도 있습니다. 공통 초기화 패턴에 대한 단축키가 시간을 절약하거나 클래스의 초기화를 의도적으로 명확하게 할 때마다 편의 초기화 프로그램을 작성하십시오.

오류 메시지가이 시점에서 명확하지 않지만 당신이 당신의 코드를 시도하고,이 문제는 저장된 속성을 초기화 편리 초기화를 사용할 수 있다는 것입니다. 작동 시키려면 선택적인 var를 만들어야합니다. 사실을

class Sub1: Base1 { 
    let b: Int 

    init(b: Int) { 
     self.b = b 
     super.init() 
    } 

    convenience override init() { 
     self.init(b:5) 
    } 
}