2
class HTMLElement {

    let name : String
    let text: String?

    //Declaring a lazy variable that has a strong reference to this closure
    lazy var asHTML: Void -> String = {
        //Optional binding here
        if let text = self.text {
             return "<\(self.name)>\(text)<\(self.name)>"
        } else {
            return "<\(self.name) >"
        }
    }

    init(name: String, text: String? = nil){
        self.name = name
        self.text = text
    }

    deinit {
        print("\(name) is being deinitialized")
    }
}

私の質問は: クロージャーが Lazy と宣言されているのはなぜですか? クロージャーで認識されていないことに関係があることはわかっていますが、作成されていないメソッドselfの場合も同じではありませんか?initself

第二に、このコード例の強い参照サイクルは正確にはどこですか?それselfは を強く参照してasHTMLいますか?もしそうなら、サイクルを引き起こす強い参照の 2 番目の部分はどこですか?

第三に、定数が値をtext変更できないのに、定数プロパティがオプションである理由は何ですか?nilnil

最後に、メソッドがユーザーから送信されたパラメーターを受け入れるために使用されている場合、text: String? = nilメソッドにパラメーターがあるとはどういう意味ですか?initinit

この長い質問で申し訳ありませんが、クロージャの強参照サイクルについて混乱しています....クラスプロパティとクラスインスタンス間の強参照サイクルは理解していますが。

4

1 に答える 1

1

1

lazy呼び出されたときにのみ作成される属性に使用されます。したがって、呼び出す前にmyClass.myLazyAttributeスペースを占有しません。これは、クラスが初期化された後に初期化されることも意味します。これは非常に便利です。

この場合、あなたが述べたように、へのlazyアクセスを取得するために使用されます。これは、インスタンスが初期化されるまで利用できないためです。selfself

2

コードがある場所からのアップルドキュメント。

クロージャーは、それらで使用される値をキャプチャします。この場合、キャプチャしselfます。クラス A とクラス B の間ではなく、それ自体とクロージャの間に強力な参照サイクルを作成します。クロージャー内の操作に非常に長い時間がかかることを想像すると、はるかに理にかなっています。実行中に何か他のことが起こり、インスタンスを deinit したい場合。しかし、クロージャーはキャプチャーselfしており、それが完了するまでインスタンスを存続させます。

を使用[unowned self] inすると、クロージャーの実行中にインスタンスを再び deinit できます。これによりアプリがクラッシュしますが。

この特定の使用に関する良い情報:リンク

クロージャーの特定のケースでは、その内部で参照される変数はクロージャーによって「所有」されることを認識する必要があります。クロージャーが存在する限り、それらのオブジェクトは存在することが保証されます。その所有権を止める唯一の方法は、【所有されていない自己】または【弱い自己】を行うことです。

ストロング・リファレンス・サイクルの本質とは:

  • あなたはクラスのインスタンスを持っています
  • インスタンスの参照カウントが 0 より大きい
  • プログラムで使用できるインスタンスへの参照はなくなりました。

またはさらに短く: インスタンスの参照カウントは、アクセス可能な参照の数よりも多くなります。

この場合、selfクロージャによってキャプチャされるため、 の参照カウントが 1 増加します。のようなことを言うことができないため、その参照にアクセスできません:closure.selfAttributeに設定することはできませんnil。クロージャーが終了したときにのみ、参照カウントが再び 1 減少します。

3

オプションの定数ですが、初期値はクラスの init メソッドで設定されます。そのため、init メソッドで値を受け取ることができますが、不変になります。これは、遅延初期化と呼ばれます。

4

これは、デフォルト値を持つ関数パラメーターです。

func someFunction(myParamWithDefaultValue : Int = 10) {
    print(myParamWithDefaultValue)
}

someFunction() // 10
someFunction(5) // 5
于 2015-11-19T06:28:18.887 に答える