1

他のクラス関数を変数として格納するクラスがある場合、参照サイクルが発生する可能性がありますか?

例えば

class ClassA {

    var i = 0

    func incrementI() {
        i++
    }
}

class ClassB {

    private var function: () -> ()

    init(function: () -> ()) {
        self.function = function
    }

    func someFunc() {
        function()
    }
}

変数関数を弱いまたは所有されていないとして ClassB に格納できないため、参照サイクルが発生する可能性がありますか? それとも、これは参照サイクル/機能に関する私の理解が不十分であることを反映しているだけですか?

4

1 に答える 1

1

参照サイクルは、まさにその名前が示すとおりです。あるオブジェクトは、元のオブジェクトを参照する別のオブジェクトを参照します。これらは、2 つ以上のオブジェクトで構成できます。

ブロックまたはクロージャーを使用して参照サイクルを簡単に作成できるのは、クロージャーで自己をキャプチャするということは、クロージャー オブジェクトが自己への参照を持っていることを意味するためです。self にもクロージャーへの参照がある場合は、参照サイクルがあります。ClassB の init でクロージャーを渡しているため、あなたの例は安全だと思います。つまり、そのクロージャーは存在しないオブジェクトへの参照を持つことができないはずです。

あなたの例がメソッドとして機能した場合、これを行うことができるので問題があります:

class ClassB {

    ...

    func setSomeFunc(function : ()->()) {
        self.function = function
    }

    func printSomething() {
        print("Something")
    }
}

...

func test() {
    var x1 = {
        print("Do Nothing")
    }
    var b : ClassB = ClassB(x1)
    var x2 = {
        b.printSomething()
    }
    b.setSomeFunc(x2)
}

この例では、外部参照を持たない x1 を作成します。

[x1]

次に、x1 への参照を使用して b を作成します。この参照は ClassB の init に追加されます。

[b]->[x1]

次に、b への参照を使用して x2 を作成します。b は x2 クロージャーでキャプチャされます。つまり、b への強い参照を保持します。

 [x2]->[b]->[x1]

ここで、新しい関数 x2 を b に割り当てます。これにより、b から x1 への参照が壊れます...

[x2]->[b]-x->[x1]

x2への参照に置き換えます。

[x2]->[b]-\    [x1]
 /\       |
  \-------/

ご覧のとおり、循環 (または循環) 参照ができました。その参照を破る唯一の方法は、b の関数メンバーを別のものを参照するように設定するか、x2 のキャプチャされた b 値を別のものに設定することです。

于 2014-12-10T13:28:17.743 に答える