SwiftUI | weak selfの効果を実験で理解する

SwiftUI

SwiftUIのweak selfの効果を実験で理解した結果を説明する。

結論

weak selfを使わないと強い参照となり、生成した全てのインスタンスが全て実行されるまでそのインスタンスがメモリに占有され続けるが、全てを実行してくれる。

weak selfを使うことで弱い参照となり、クラスのインスタンスを新しく生成するごとに前に生成したクラスのインスタンスが消えてメモリが開放される。

どちらを使うかはそれぞれの特徴をわかった上で決めれば良い。

実験1 weak selfを使わない(強い参照)

  1. クラスのインスタンスが生成されてから10秒後に{ }の中を実行させる。
  2. この self はクラスに対して強く参照を保持する。例えばユーザーがビュー2を何回も表示することでクラスのインスタンスが何個も作成されるが、それぞれのインスタンスが生成されたときから10秒経過するまではそれぞれが参照を保持するためその間メモリも占有し続ける。
import SwiftUI

struct ContentView: View {
    var body: some View {
        NavigationView {
            NavigationLink("▶ クラスを作る", destination: ビュー2())
        }
    }
}

struct ビュー2: View {
    @StateObject var 新しいクラス = クラス()
    var body: some View {
        Text("新しくクラスを作ったよ。print結果を見てね。")
    }
}

class クラス: ObservableObject {
    @Published var なまえ: String? = nil
    init() {
        let selfのメモリアドレス = Unmanaged.passUnretained(self).toOpaque()
        print("クラスが初期化されました。", selfのメモリアドレス)
        実験コード()
    }
    
    deinit {
        let selfのメモリアドレス = Unmanaged.passUnretained(self).toOpaque()
        print("クラスが消えました。", selfのメモリアドレス)
    }
    
    func 実験コード() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 10) {  // ? 1
            self.なまえ = "私はヨシヒコだ"                         // ? 2
            print(self?.なまえ)
        }
    }

}

生成した全てのインスタンスが全て実行されるまでそのインスタンスがメモリに占有され続けるが、全てを実行してくれる。

クラスが初期化されました。 0x00006000001a05a0
クラスが初期化されました。 0x00006000001ad7a0
クラスが初期化されました。 0x000060000015d5c0
クラスが初期化されました。 0x0000600000157540
クラスが初期化されました。 0x00006000001ac510
Optional("私はヨシヒコだ")
クラスが消えました。 0x00006000001a05a0
Optional("私はヨシヒコだ")
クラスが消えました。 0x00006000001ad7a0
Optional("私はヨシヒコだ")
クラスが消えました。 0x000060000015d5c0
Optional("私はヨシヒコだ")
クラスが消えました。 0x0000600000157540
Optional("私はヨシヒコだ")

実験2 weak selfを使う(弱い参照)

  1. [weak self] in を付ける。
  2. この self は弱い参照。self はOptional型になるので self? にする。
import SwiftUI

struct ContentView: View {
    var body: some View {
        NavigationView {
            NavigationLink("▶ クラスを作る", destination: ビュー2())
        }
    }
}

struct ビュー2: View {
    @StateObject var 新しいクラス = クラス()
    var body: some View {
        Text("新しくクラスを作ったよ。print結果を見てね。")
    }
}

class クラス: ObservableObject {
    @Published var なまえ: String? = nil
    init() {
        let selfのメモリアドレス = Unmanaged.passUnretained(self).toOpaque()
        print("クラスが初期化されました。", selfのメモリアドレス)
        実験コード()
    }
    
    deinit {
        let selfのメモリアドレス = Unmanaged.passUnretained(self).toOpaque()
        print("クラスが消えました。", selfのメモリアドレス)
    }
    
    func 実験コード() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 10) { [weak self] in  // ? 1
            self?.なまえ = "私はヨシヒコだ"                                       // ? 2
            print(self?.なまえ)
        }
    }

}

クラスのインスタンスを新しく生成するごとに前に生成したクラスのインスタンスが消えてメモリが開放される。その代わり最後に生成したインスタンス以外の実行結果はnilになる。

クラスが初期化されました。 0x0000600000fde100
クラスが初期化されました。 0x0000600000f57180
クラスが消えました。 0x0000600000fde100
クラスが初期化されました。 0x0000600000f46550
クラスが消えました。 0x0000600000f57180
クラスが初期化されました。 0x0000600000f52520
クラスが消えました。 0x0000600000f46550
クラスが初期化されました。 0x0000600000f5eaf0
クラスが消えました。 0x0000600000f52520
nil
nil
nil
nil
Optional("私はヨシヒコだ")

まとめ

SwiftUIのweak selfの効果を実験で理解した結果を説明した。

コメント

タイトルとURLをコピーしました