Open6

iOSアプリ開発におけるメモリリーク対策

kamimikamimi

まず注意すべき点

  • ただし必ずしもこれらを使っているからと言って、メモリリークが起きるわけではない
  1. Delegateパターン

weak var XXDelegate?

  1. クロージャ
  • キャプチャリストをつけて、弱参照にする

[weak self]

  • メモリリークで気をつけるべきところのより詳細
    • ライブラリを使用して、開発中に検知することも可能

https://techlife.cookpad.com/entry/2020/03/03/115000

  1. tableViewのセル数が多く、画像を読み込む必要がある場合
  • 全てのセル分の画像を読み込むと、メモリを一気に枯渇させてしまう恐れがある
  • SwiftUIの場合は、LazyVStackまたはLazyHStackを使用することで、Lazyロードを実現することができる

https://www.yururiwork.net/archives/1212

kamimikamimi

メモリリークが発生しているかどうかの確認方法

  1. deinitを使用して、メモリが解放されていることを確認する
  • それによって、循環参照が起きているかどうかを確認することができる

  1. Xcodeの下にあるメモリデバッグのマークを押して確認できる
  • 紫の⚠️が出ているとメモリリークしている
  • ただし必ずしもXcodeのツールで見て紫でなかったからといって、メモリリークしていないとは限らない!!

https://dev.classmethod.jp/articles/ios-memory-leak-check-and-prevent-190508/

  • コードのどの行でメモリリークが発生しているかは、Malloc Stack loggingをEdit Schemeからオンにすると確認できる

https://qiita.com/MaShunzhe/items/8073d32d7aee28578cab


  1. Xcodeに付属しているInstrumentsを使用することでも、メモリリークを検知できる

https://kerubito.net/technology/3298

動画
https://www.youtube.com/watch?v=sp8qEMY9X6Q

kamimikamimi

SwiftUIアプリを作っていて、早速メモリリークが発生

  • 紫のマークが出ており、malloc loggingのbacktrackを見たが、なぜか初回起動の@mainで発生している(自分で書いたのは1行だけなのだが)

コード

import SwiftUI

@main
struct XXApp: App {
    var body: some Scene {
        WindowGroup {
            SampleView()
        }
    }
}
  • Xcodeで確認した結果

  • $main()の横にカーソルをフォーカスすると、矢印が出てくるので、そこを押すと該当コードにジャンプできる

修正プロセス

  • クロージャを使用している場所で、[weak self]を忘れている箇所がないか確認
    • 全てにキャプチャリストをつけたが、まだメモリリークする
  • セグメンテッドコントロールを使用している箇所のViewの呼び出しコードをコメントアウトしたところ、発生しなくなった
    • Viewの呼び出し方か、ViewModelの渡し方が問題か?
    • セグメンテッドコントロールを使用してミニアプリをもう一度作り直してみたところ、ViewModelを渡していなくてもメモリリークは発生していた
  • 選択したセグメントによって切り替えるViewの部分を、セグメンテッドコントールを定義しているViewと同じViewのstructではなく、別のstructとして定義すると、メモリリークしなくなる!
private var content: some View {
        Group {
            switch selectedIndex {
            case .A:
                SampleAView(viewModel: SampleAViewModel())
            case .B:
                SampleBView(viewModel: SampleBViewModel())
            }
        }
    }