簡體   English   中英

使用協調器模式時奇怪的保留周期

[英]Weird retain cycle when using the Coordinator pattern

我正在使用MVVM +協調器構建新的應用程序。 具體來說,我使用的是https://github.com/daveneff/Coordinator上的Coordinator模式。

在頂層,我有一個AppCoordinator,可以啟動子協調器RegisterCoordinator。 注冊流程完成后,AppCoordinator會切換其導航器的根視圖控制器,並且應該從內存中釋放注冊流程中使用的協調器和視圖控制器。

final class AppCoordinator: CoordinatorNavigable {
  var dependencies: AppDependencies
  var childCoordinators: [Coordinator] = []
  var rootViewController = UINavigationController()
  var navigator: NavigatorType

  init(window: UIWindow, dependencies: AppDependencies) {
    self.dependencies = dependencies
    navigator = Navigator(navigationController: rootViewController)

    dependencies.userManager.delegate = self

    window.rootViewController = rootViewController
    window.makeKeyAndVisible()
  }

  func start() {
    if dependencies.properties[.user] == nil {
      // Logged out state
      let vc = AuthFlowViewController.instantiate(storyboardName: Constants.Storyboards.authFlow)
      vc.delegate = self
      navigator.setRootViewController(vc, animated: false)
    } else {
      // Logged in
      let vc = HomeViewController.instantiate(storyboardName: Constants.Storyboards.home)
      vc.viewModel = HomeViewModel(dependencies: dependencies)
      navigator.setRootViewController(vc, animated: false)
    }

    childCoordinators = []
  }
}

extension AppCoordinator: UserManagerDelegate {
  func authStateChanged() {
    // User logged in or logged out; show the correct root view controller
    start()
  }

  func userChanged() {}
}

extension AppCoordinator: AuthFlowViewControllerDelegate {
  func login() {
    dependencies.userManager.changeUser(newUser: User(id: 1, name: "Kevin"))
  }

  func startRegisterFlow() {
    let registerCoordinator = RegisterCoordinator(dependencies: dependencies, navigator: navigator)
    pushCoordinator(registerCoordinator, animated: true)
  }
}

同時,RegisterCoordinator只需將多個視圖控制器推入導航器的堆棧中:

class RegisterCoordinator: CoordinatorNavigable {
  var dependencies: AppDependencies
  var childCoordinators: [Coordinator] = []
  var navigator: NavigatorType

  let rootViewController = PhoneInputViewController.instantiate(storyboardName: Constants.Storyboards.authFlow)

  init(dependencies: AppDependencies, navigator: NavigatorType) {
    self.dependencies = dependencies
    self.navigator = navigator
    rootViewController.delegate = self
  }

  func start() {}
}

extension RegisterCoordinator: PhoneInputViewControllerDelegate {
  func phoneInputDone() {
    let vc = PhoneValidationViewController.instantiate(storyboardName: Constants.Storyboards.authFlow)
    vc.delegate = self
    navigator.push(vc, animated: true)
  }
}

extension RegisterCoordinator: PhoneValidationViewControllerDelegate {
  func phoneValidationDone() {
    let vc = GenderSelectionViewController.instantiate(storyboardName: Constants.Storyboards.authFlow)
    vc.viewModel = GenderSelectionViewModel(dependencies: dependencies)
    navigator.push(vc, animated: true)
  }
}

整個注冊流程完成后,最后一頁可以保存用戶,這將觸發authStateChanged中的authStateChanged方法,然后該方法將更改導航器的rootViewController。 然后,這也應該清理其子協調器。

盡管可悲的是,盡管已正確釋放了流程中的其他視圖控制器,但RegisterCoordinator及其rootViewController(PhoneInputViewController)仍保持活動狀態。

我嘗試在start方法中手動執行childCoordinators = [] ,以確保AppCoordinator沒有對RegisterCoordinator的強引用,但即使這樣也無濟於事。

我不知道保持強引用的是什么,導致保留周期/內存泄漏。 我在GitHub上有一個超級極簡版的應用程序,基本上刪除了所有內容,除了顯示問題的基本要點外: https : //github.com/kevinrenskers/coordinator-problem

首先,您要在Coordinator.self第132行的一個塊中捕獲協調器:

在此處輸入圖片說明

我使用調試內存圖發現了這一點:

在此處輸入圖片說明

還有PhoneInputViewController仍然存在,您可以檢查為什么使用相同的方法

我無法完全理解您的協調器模式實現的工作原理,但是最好不要保留對控制器的強大引用。

我一直在使用一些實現,其中控制器僅由UINavigationController的堆棧保留,而window保留UINavigationController

它可以確保您的控制器在彈出/更換后始終會死亡。

在你的情況,我會試圖使啟動childCoordinatorsCoordinator ,以保持弱裁判給你的控制器。

rkyr的回答將我推向了正確的方向,我找到了問題的根源,並將包含修復程序的PR發送到了我正在使用的原始Coordinator庫中。 因此,在那里進行單線修復: https : //github.com/daveneff/Coordinator/pull/1

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM