モノトーンの伝説日記

Apex Legends, Splatoon, Programming, and so on...

<mini> SwiftUI + Combine (@Published) でメモリーリーク

 ※ SwiftUI 2.0 の iOS 14+, macOS 11+ (Big Sur / Monterey), tvOS 14+, watchOS 7+ のみ解決方法を掲載します。

サンプルコード

import SwiftUI

final class LoginViewModel: ObservableObject {
  var cancellables = Set<AnyCancellable>()

  // MARK: - Input

  @Published
  var email = ""

  @Published
  var password = ""

  // MARK: - Output

  @Published
  private(set) var canLogin = false

  init() {
    $password.map { password in
      let count = password.count
      return count >= 8 || count <= 32
    }
    .assign(to: \.canLogin, on: self)
    .store(in: &cancellables)
  }
}

 これ、リークします。具体的には「.assign(to: \.canLogin, on: self)」で self への強参照 strong reference を持っているから。

 書き換えは、以下の通り

  init() {
    $password.map { password in
      let count = password.count
      return count >= 8 || count <= 32
    }
    .assign(to: &$canLogin)
  }

 一応 memory management 見ておくかーって思ってみたらリークしてるので、Combine あたり怪しいな、って思ってたんですが、assign は強参照を常に持つとはね。一応詳しい記事は以下に。

www.swiftbysundell.com

 WWDC 2021 の Swift in ARC も必聴です。

developer.apple.com