実行したコード:
swift
import Foundation
// 引数のクロージャを非同期実行する関数
// 実際の場面では非同期実行することが多いので、今回も非同期実行にする
struct A {
static func a(_ closure: @escaping () -> Void) {
DispatchQueue.main.async {
closure()
}
}
}
// Aを利用するクラス
// 実際の場面では ViewModel とか?
class B {
// 検証に使用する変数
var int: Int = 0
var closure: () -> Void = {}
// MARK: -
// インスタンスの番号
let version:Int
init(_ version: Int) {
self.version = version
}
// インスタンスが解放されるか調べるために、 deinit したか分かるようにする
deinit {
print("deinit \(version)")
}
// MARK: -
func b() {
switch version {
case 0:
A.a {
_ = 1 + 1
}
case 1:
A.a {
self.int = 1
}
case 2:
A.a {
self.int = self.int * 2
}
case 3:
A.a {
self.closure = {}
}
case 4:
A.a {
self.closure()
}
case 5:
A.a {
self.closure = { self.int = 1 }
}
case 6:
// 循環参照が起こる基本的なケース
// A.a() は呼び出さない
// case 5 と比較する目的
self.closure = { self.int = 1 }
default:
print("not implemented")
}
}
}
(0...6).forEach { i in
var b:B? = B(i)
b?.b()
b = nil // 循環参照が起きていなければ、インスタンスが解放されて deinit が呼ばれる
}
実行結果:
deinit 0
deinit 1
deinit 2
deinit 3
deinit 4
closure の中で self.int = 1
みたいなことしても循環参照になってない!