3

次のように、クロージャーで保持サイクルを実験しています

 class Sample {
        deinit {
            print("Destroying Sample")
        }

        func additionOf(a: Int, b:Int) {
            print("Addition is \(a + b)")
        }

        func closure() {                
          dispatch_async(dispatch_get_global_queue(0, 0)) { [weak self] in
            self?.additionOf(3, b: 3)   
            usleep(500)                 
            self?.additionOf(3, b: 5)  
          }
        }
    }

後である時点で、私はやっています

var sample : Sample? = Sample()
sample?.closure()

dispatch_async(dispatch_get_global_queue(0, 0)) {
  usleep(100)
  sample = nil
}

出力は次のようになります。

Addition is 6
Destroying Sample

これは理解できますselfself?.additionOf(3, b:5)

[weak self]次のように参照する別の変数を作成して、クロージャー内で変更を加えた場合

dispatch_async(dispatch_get_global_queue(0, 0)) { [weak self] in
   guard let strongSelf = self else { return }
   strongSelf.additionOf(3, b: 3)
   usleep(500)
   strongSelf.additionOf(3, b: 5)
}

今回の出来上がりは

Addition is 6
Addition is 8
Destroying C

私の質問は、なぜstrongSelfnil out after でないのかということですsample = nil。前にクロージャー内に取り込まれているからでしょうかsample = nil

4

1 に答える 1

3

2番目の例を考えてみましょう:

dispatch_async(dispatch_get_global_queue(0, 0)) { [weak self] in
    guard let strongSelf = self else { return }
    strongSelf.additionOf(3, b: 3)
    usleep(500)
    strongSelf.additionOf(3, b: 5)
}

これは一般的なパターンであり、「selfが割り当て解除された場合はreturnすぐに、そうでない場合は強い参照を確立しstrongSelf、閉鎖が完了するまでこの強い参照を維持する」ことを効果的に示しています。

したがって、あなたの例では、このディスパッチされたブロックが開始されたときでselfはなかったので、それを参照するように割り当てるとすぐに、このオブジェクトへの2つの強い参照、元の参照とこのクロージャ内のこの新しい参照の両方ができました。nilstrongSelfSamplesamplestrongSelf

sampleしたがって、他のスレッドがこのオブジェクトへの独自の強い参照 を削除してSampleも (範囲外になるか、明示的に に設定sampleすることによりnil)、このstrongSelf強い参照は引き続き存在し、オブジェクトの割り当てが解除されないようにします (または、少なくともこのディスパッチされたブロックは終了します)。

上記のコメントでは、次のように尋ねます。

strongSelfself が出てから変更されない理由はまだわかりませんnil...

nil他の強い参照 (元の強い参照であったとしても) が に設定されたという理由だけで、強い参照が に設定されることはありませんnil。設定された参照の動作は参照にnilのみ適用されweak、強い参照には適用されません。

コードがsample = nil最初のスレッドで実行されるときは、強い参照を削除するだけです。オブジェクトなどは削除しません。強い参照を削除するだけです。そして、ディスパッチされたブロックが独自の強参照を持つようになったのでsample = nil、2 つの強参照を持っていたオブジェクトには 1 つの強参照 (strongSelfディスパッチされたブロック内の参照) しか残っていません。この最後の強い参照が削除された場合にのみ、オブジェクトの割り当てが解除さdeinitれ、呼び出されます。

于 2016-08-05T04:41:49.083 に答える