1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

weak selfについて

Last updated at Posted at 2023-09-07

強参照と弱参照は意識して使い分けてる?と言われ、ドキッとした。

2回目言われると心臓が止まってしまうので理解が曖昧な今
深夜テンションで雑にまとめる!!!

weak selfがないと何が起こるのか

「循環参照してメモリリークする」です。 なんのこっちゃ?

そのまえにARCとは

swiftではARC(Auto Reference Counting)という仕組みを用いて、自動でメモリの管理を行なってくれています。そのお陰で、私でも脳死でコードを書くことが出来たんですね。

このARCはランタイム時に自動で参照をカウントする仕組みで、
例えば、

class Hoge {
    init() {
        print("init")
    }
    deinit {
        print("deinit")
    }
}

こういうクラスがあったとしましょう。

var ref1: Hoge? = Hoge()
var ref2: Hoge? = ref1
var ref3: Hoge? = ref1

この時、Hoge()は

  • ref1
  • ref2
  • ref3
    の3つから参照されています。(参照カウンター = 3)

Hogeが解放される時にdeinitが呼ばれます。
deinitを呼び出すにはどうすれば良いでしょうか。

キルするには参照している箇所をなくせば良いですね。

スクリーンショット 2023-09-07 0.03.42.png

ref1にnilを入れてみてもdeinitは呼ばれていません。

スクリーンショット 2023-09-07 0.03.57.png

ref1とref2にnilを入れてみてもdeinitは呼ばれていません。

スクリーンショット 2023-09-07 0.04.05.png

ref1,ref2,ref3にnilを入れて初めて参照されている箇所がなくなり、Hogeをキルすることが出来ました。

これがざっくりとした参照カウントという概念
(説明が面倒なので、他のわかりやすい記事を見てね)

これはインターンのメンターさんに教えていただいた

class HogeViewController: UIViewController {
    let hogeView: HogeView = .init()

    var counter: Int = 0

    // 強参照
    hogeView.state = { _ in
        self.counter += 1
    }
}

class HogeView: UIView {
    var state: (() -> Void)?

    // ボタンが押された時、ここが呼ばれるとする
    func button() {
        state?()
    }
}

hogeViewのbuttonが呼ばれた時、

hogeView.state = { _ in
    self.counter += 1
}

が動く。
この時のselfはHomeViewControllerのことですな。

hogeView.state内のHomeViewControllerのcounterを強参照しています。(参照カウンターが増える)

この時、HomeViewControllerが解放されようとしますが、参照カウンター(HomeViewControllerが無くなると困るよ〜って言ってる箇所)が0にならずメモリ解放ができません。これによりメモリリーク(使ってないのにメモリが確保されている状態)に陥る。

weak selfを使うとどうなるのか

参照カウンターが増えません。
つまり、HomeViewControllerと運命を共にするさだめの、参照箇所は参照カウンターが増える必要はないですね。

class HogeViewController: UIViewController {
    let hogeView: HogeView = .init()

    var counter: Int = 0

    // 弱参照
    hogeView.state = { [weak self] in
        self?.counter += 1
    }
}

ここで、IBOutlet について、なぜweak selfがついているのか疑問に思いました。

@IBOutlet weak var myView: UIView!

UIKitを使ってるとこんなコードをよく見ますね

下記の記事を参考にしてください
https://qiita.com/chocovayashi/items/a96adc1356b7c45524b7

参考記事の結論がわかりやすかったので引用

IBOutletのViewをremoveする予定がなければ、適当でOK
IBOutletのViewをremoveし、その後は使わなければ、@IBOutlet weak var hogehoge: HogeView!
IBOutletのViewをremoveし、その後また使うなら@IBOutlet var hogehoge: HogeView!
なにも予想できない場合は、@IBOutlet weak var hogehoge: HogeView?

参考
https://zenn.dev/mhackit/articles/a0b1c6e780c3c6aabe45
https://qiita.com/reo0612/items/b0d1ee00ebf3a0e7c857

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?