2016-07-11 6 views
6

대 "failable 초기화 '초기화하기()가'비 failable 초기화를 재정의 할 수 없습니다." let a = A()과 같이 사용하면 초기화 프로그램이 예상대로 호출됩니다.스위프트 : 나는</p> <pre><code>public class A: NSObject { public class X { } public init?(x: X? = nil) { } } </code></pre> <p>을 모두 괜찮 선언하면 기본 매개 변수

이제 중첩 클래스 X을 private로 설정하고 매개 변수화 된 init도 추가하고 싶습니다 (당연히 있어야합니다). 그러나 단순한 init?()은 예전처럼 공개적으로 사용할 수 있어야합니다. 그래서

public class B: NSObject { 
    private class X { } 
    private init?(x: X?) { } 
    public convenience override init?() { self.init(x: nil) } 
} 

쓰기하지만이 init?() 초기화에 오류를 제공합니다 : failable 초기화 '초기화를() 재정의 초기화가 NSObject에서 public init() 인과 비 failable 초기화을 무시할 수 없습니다.

어떻게 효과적으로 이니셜 라이저 A.init?()을 충돌없이 선언 할 수 있지만 B.init?()을 선언 할 수 있습니까?

보너스 질문 : 왜 내가 사용할 수없는 이니셜 라이저를 사용할 수없는 이니셜 라이저를 덮어 쓸 수 없습니까? 그 반대는 합법적입니다. fable 이니셜 라이저를 재정의 할 수 없으며 강제로 super.init()!을 사용해야하므로 런타임 오류가 발생할 수 있습니다. 나에게 함수의 확장은 실패의 기회를 더 많이 가져 오기 때문에 하위 클래스에 초기화 가능한 이니셜 라이저를 부여하는 것이 더 현명하다고 느낀다. 그러나 어쩌면 여기서 뭔가를 놓치고 있습니다. 설명이 크게 감사하겠습니다.

+0

'override'는 수퍼 클래스에서 같은 서명을 가진 메소드를 의미합니다. 그러나'NSObject'에는'init? '이 없습니다. – vadian

+0

@vadian : 예,하지만'override'를 생략하면 'override override'키워드가 필요하다는 오류 메시지가 생성되므로 무시됩니다. 수정 - 다른 오류를주는'override' 삽입입니다. 또한, fabled가 아닌 init로 대체 할 수 있지만 반대는 허용되지 않습니다. – Stefan

답변

2

약간의 만만치 후에 나는 이해한다고 생각합니다. "초기화 요구 사항 '의 init() 만이 아닌 최종 클래스'A '에서 required 초기화에 의해 만족 될 수있다"

protocol I { 
    init() 
} 

class A : I { 
    init() {} 
} 

이 오류를 제공합니다 :이 초기화하고 구현하는 클래스를 필요로하는 프로토콜을 생각해 보자 . 우리가 보면 지금

class A : I { 
    required init() {} 
} 

을 :

class B : A { 
    // init() is not inherited 
    init(n: Int) {} 
} 

그래서 우리는 Arequired 우리의 초기화를 할 필요가 : 당신은 항상 초기화를 상속하지 않습니다 A의 서브 클래스를 선언 할 수 있기 때문에 이것은 의미가 있습니다

public class NSObject : NSObjectProtocol { 
    [...] 
    public init() 
    [...] 
} 
다음 NSObject 인터페이스에서 우리는 초기화가 하지 required 것을 볼 수 있습니다 심지어 우리는 I 프로토콜을 준수하는 NSObject을 확장 할 수 있습니다 : 지금 여기에 이상한 일이 온다

class MyObject : NSObject { 
    init(n: Int) {} 
} 

MyObject() // Error: Missing argument for parameter 'n:' in call 

: 16,

우리는 그것을 서브 클래스 다른 초기화를 추가하고 정상 하나를 사용하려고하면이를 확인할 수 있습니다 그것은이 초기화가 필요하지 않습니다하지만 :

extension NSObject : I {} // No error (!) 

을 솔직히이 버그 ObjC의 상호 운용성이 작동하기위한 요구 사항 중 하나라고 생각합니다 (편집 : 그것은 버그 이미 최신 버전에서 수정).이 오류는 불가능합니다

extension I { 
    static func get() -> Self { return Self() } 
} 

MyObject.get() 
// Runtime error: use of unimplemented initializer 'init()' for class '__lldb_expr_248.MyObject' 

이제 실제 질문에 답 : 두 번째 코드 샘플에서

를, 컴파일러는 당신이 failable 초기화와 비 failable을 무시할 수 없다는 권리입니다.

처음에는 실제로 이니셜 라이저를 무시하지 않고 (override 키워드 없음) 대신 다른 하나를 상속 할 수없는 새 값을 선언합니다.

나는이 글을 많이 썼다. 나의 대답의 첫 부분이 당신의 질문과 관련이 있는지조차 모르겠지만 어쨌든 버그를 발견하는 것이 좋다.

내가 대신이 작업을 수행하는 것이 좋습니다 :

public convenience override init() { self.init(x: nil)! } 

는 또한 스위프트 참조의 Initialization section를 보라.

내가

public convenience init?(_: Void) { self.init(x: nil) } 

을 선언하고

let b = B(()) 

또는

let b = B() 
처럼 사용할 수 있습니다
+0

자세한 답변 해 주셔서 감사합니다. 근본적인 문제는 외부 리소스 ('NSCoding' ...)가 포함되어 있기 때문에 내 하위 클래스 **의 초기화 프로그램이 ** 실패 할 수 있기 때문에 이니셜 라이저가 성공했는지 테스트하는 것이 필요합니다. 그러나'Void' 매개 변수를 사용하여 제 "PS"부록을 살펴보십시오. – Stefan

+0

Swift 3.0-dev (_error : 이니셜 라이저 요구 사항 'init()' '에서 위의 ('protocol I {init()}'뒤에'extension NSObject : I {}'} _does_ 오류가 발생했습니다. final이 아닌 클래스 'NSObject'__에서'required' 이니셜 라이저만으로 만족할 수 있습니다. 그래서 수정 된 것 같습니다. – dfri

+0

@dfri 오, 괜찮습니다. – Kametrixom

5

내가 나를 위해 문제를 해결하는 방법입니다 0

- 서명이 (일종의) 다르므로 논리적이므로 여기를 무시하지 마십시오. Void 매개 변수 만 사용하고 호출에서 생략하면 조금 이상하게 느껴지지만 ... 결국 말은 의미를 정당화합니다. :-)

+0

감사합니다. 덕분에,이 항목은 빈 내용으로 초기화하지 말아야하는 몇 개의 관리 객체 클래스가있는 영역 데이터베이스 모델에 매우 유용합니다. 값. 이 양식을 사용하면 값 필드를 사용하여 슈퍼 클래스 이니셜 라이저를 내 연결 가능 객체와 구별 할 수 있으므로 Realm Object 생성자를 init (value : Any) –