web-dev-qa-db-ja.com

'super.initがselfを初期化する前にメソッド呼び出しでselfを使用する'、メソッド呼び出しを通じてプロパティを初期化できません

とにかく、クラスのインスタンスプロパティを設定するinitメソッド内でメソッドを呼び出す方法があるのは不思議です。基本的に、UIViewをサブクラス化し、initにいくつかのサブビューを追加するクラスがあり、それらのサブビューの一部はクラスのインスタンス変数です。

class MyView: UIView {
    var collectionView: UICollectionView

    convenience init () {
        self.init(frame:CGRectZero)
    }

    override init (frame : CGRect) {
        super.init(frame : frame)

        addSubviews()
    }

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        addSubviews()
    }

    func addSubviews (){
        self.collectionView = UICollectionView()

    }
}

ここで問題は、クラスの内部プロパティを初期化する前にsuper initを呼び出せない(super.init呼び出しでプロパティ 'self.collectionView'が初期化されない)ことですが、カスタムメソッドを呼び出してこれらの変数を初期化することもできません。 super.initは、その初期化の前にselfを使用できないためです。インスタンス変数をオプションにすることもできますが、常に初期化されることがわかっているため、あまり洗練されていないようです(さらにいくつかありますが、これは単純化されたバージョンです)。インスタンス変数をすべてオプションにせずにこれを達成する方法はありますか?

編集:

最終的に私の質問は、なぜSwiftは、super.initを呼び出す前にメソッドの呼び出しを許可しないのでしょうか?違いは何ですか?

override init (frame : CGRect) {
    addSubviews()
    super.init(frame : frame)
}

final func addSubviews (){
    self.collectionView = UICollectionView()
}

そして

override init (frame : CGRect) {
    self.collectionView = UICollectionView()
    super.init(frame : frame)
}
13
Kevin DiTraglia

フォームのドキュメント:

Swiftのコンパイラは、2つの初期化がエラーなしで完了したことを確認するために、4つの有用な安全性チェックを実行します。

安全チェック1指定された初期化子は、スーパークラスの初期化子に委譲する前に、そのクラスによって導入されたすべてのプロパティが初期化されていることを確認する必要があります。

Super.init()を呼び出す前にインスタンス変数の値を設定する必要があります。このアクションの後で、インスタンスメソッドを呼び出すためにアクセスします。あなたの場合、これを行うことができます:

_override init (frame : CGRect) {
    self.collectionView = UICollectionView()
    super.init(frame : frame)
    // Now you can call method
    self.someMethod()
}
_

質問の編集用に追加:

安全上の理由から、super.init()を呼び出す前にメソッドを呼び出すことはできません。それを行う場合、メソッドは親クラスでまだ初期化されていないいくつかのプロパティを使用できます

23
Alexey Pichukov