gpt4 book ai didi

swift - 为什么旧 View 模型会响应通知?

转载 作者:行者123 更新时间:2023-11-30 11:52:10 27 4
gpt4 key购买 nike

我正在使用 MVVM 创建一个举重计算器应用程序 (Swift 4),并且已经尝试了 2 天来找出为什么本应死亡的 View 模型仍在响应 UserDefaults.defaultsDidChange事件通知。

enter image description here

  1. 我启动应用程序:
    • 启动时,在 AppDelegate 中,我创建一个新的 lift 事件对象,并使用它为 `CalculatorViewController' 初始化一个新的 CalculatorLiftEventViewModelFromLiftEvent:
  2. 我计算升力并保存
  3. 我点击 + 按钮创建新的电梯:
    • 这会导致创建一个新的空电梯事件对象
    • 这个新的 lift 事件对象用于初始化新的 CalculatorLiftEventViewModelFromLiftEvent 对象
    • 然后,这个新的 CalculatorLiftEventViewModelFromLiftEvent 会分配给 CalculatorViewController 的 viewModel 属性,替换应用启动时创建的属性
    • 计算器屏幕上的值已清零,准备输入新的电梯事件
  4. 我点击“设置”按钮转至“设置”,在其中更改与当前提升事件关联的公式。
  5. 新公式将保存为默认值,并且会触发 UserDefaults.defaultsDidChange 通知
  6. 这是我无法弄清楚的部分:原始 View 模型仍然存在,并且仍在监听 UserDefault 通知。当我关闭“设置”屏幕并返回“计算器” View 时,先前已清除的电梯事件的值现在会重新出现。

以下是点击计算器屏幕上的 +(新)按钮时会发生的情况:

@objc fileprivate func onNewButtonTapped(_ sender: UIBarButtonItem) {
let newLiftEvent = dataManager.createNewLiftEvent()
viewModel = CalculatorLiftEventViewModelFromLiftEvent(withLiftEvent: newLiftEvent, dataManager: dataManager)

setupView()
}

以下是 CalculatorLiftEventViewModelFromLiftEvent 的初始化方式:

init(withLiftEvent liftEvent: LiftEventRepresentable, dataManager: CoreDataHelper) {
self.modelLiftEvent = liftEvent
self.liftName = Dynamic("\(modelLiftEvent.lift.liftName)")
self.weightLiftedTextField = Dynamic(modelLiftEvent.liftWeight.value)
self.repetitionsTextField = Dynamic("\(modelLiftEvent.repetitions)")
self.oneRepMaxTextField = Dynamic(modelLiftEvent.oneRepMax.value)
self.unitsTextField = Dynamic("\(UserDefaults.weightUnit())")
self.weightPercentages = Dynamic( [ : ] )
self.dataManager = dataManager

super.init()

subscribeToNotifications()
}

更新:以下是 CalculatorLiftEventViewModelFromLiftEvent 中的 deinitaddObserver。请注意,我没有使用基于 block 的观察。

deinit {
print("I got to the deinit method")
unsubscribeFromNotifications()
}

func subscribeToNotifications() {
NotificationCenter.default.addObserver(self,
selector: #selector(liftNameDidChangeNotification(_:)),
name: NSNotification.Name(rawValue: LiftEventNotifications.LiftNameDidChangeNotification),
object: nil)

NotificationCenter.default.addObserver(self,
selector: #selector(weightUnitDidChangeNotification(_:)),
name: NSNotification.Name(rawValue: LiftEventNotifications.WeightUnitDidChangeNotification),
object: nil)

NotificationCenter.default.addObserver(self,
selector: #selector(roundingOptionDidChangeNotification(_:)),
name: NSNotification.Name(rawValue: UserDefaultsNotifications.roundingOptionDidChangeNotification),
object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.defaultsDidChange), name: UserDefaults.didChangeNotification,
object: nil)
}

--- 结束更新

我在转到 SettingsViewController 时传递了 modelLiftEvent:

 override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let identifier = segue.identifier {
switch identifier {
case a:...
case b:...
case "SettingsSegue":
if let nav = segue.destination as? UINavigationController {
let destinationViewController = nav.topViewController as! SettingsViewController
destinationViewController.dismissalDelegate = self

let settingsViewModel = SettingsViewModelFromLiftEvent(withLiftEvent: self.viewModel.modelLiftEvent)
destinationViewController.settingsViewModel = settingsViewModel
destinationViewController.dataManager = dataManager
settingsViewModel.dataManager = dataManager
}

最后,在 CalculatorLiftEventViewModelFromLiftEvent 中,我在此处放置了一个断点,因为当 View 模型听到 UserDefaults.defaultsDidChange 通知时会调用该断点。此时,我还验证了此 CalculatorLiftEventViewModelFromLiftEvent 是旧的,而不是我点击 + 按钮时创建的新的:

@objc func defaultsDidChange(_ notification: Notification) {
let oneRepMax = modelLiftEvent.calculateOneRepMax()

guard oneRepMax.value != 0.0 else { return }

let weightPercentages = getWeightPercentages(weight: oneRepMax.value)
self.weightPercentages.value = weightPercentages

weightLiftedTextField.value = modelLiftEvent.liftWeight.value
repetitionsTextField.value = "\(modelLiftEvent.repetitions)"
oneRepMaxTextField.value = modelLiftEvent.oneRepMax.value
}

我已经阅读了一堆有关对象生命周期的文档,但没有找到任何有帮助的内容。我希望当创建新的 CalculatorLiftEventViewModelFromLiftEvent 并将其分配给“CalculatorViewController”的 viewModel 属性时,它将替换对旧属性的引用,并且它将不再存在。显然,事实并非如此。

有谁知道为什么当我从没有值(0.0 除外)的计算器 View (步骤 3)进入设置然后返回时,会显示之前的提升事件值?

最佳答案

我修复了在清除计算器、更改默认公式并返回计算器屏幕后显示之前的 liftEvent 的问题。

CalculatorViewController 上,当点击 + 按钮时,我不是创建一个新的 viewModel 并将其分配给 viewModel 属性,而是要求我的 AppDelegate 创建一个新的 CalculatorViewControllerCalculatorLiftEventViewModelFromLiftEvent 通过使用 launchCalculatorViewController 方法在应用启动时执行此操作。

CalculatorViewController中的原始代码:

@objc fileprivate func onNewButtonTapped(_ sender: UIBarButtonItem) {

let newLiftEvent = dataManager.createNewLiftEvent()
viewModel = CalculatorLiftEventViewModelFromLiftEvent(withLiftEvent: newLiftEvent, dataManager: dataManager)

self.percentagesTableView.reloadData()

setupView()
}

现在 CalculatorViewController 中的新代码:

@objc fileprivate func onNewButtonTapped(_ sender: UIBarButtonItem) {

(UIApplication.shared.delegate as? AppDelegate)?.launchCalculatorViewController()

}

AppDelegate中:

func launchCalculatorViewController() {
self.window = UIWindow(frame: UIScreen.main.bounds)
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
if let initialViewController: CalculatorViewController = mainStoryboard.instantiateInitialViewController() as? CalculatorViewController {

self.window?.rootViewController = initialViewController

let liftEvent = dataManager.createNewLiftEvent()
let viewModel = CalculatorLiftEventViewModelFromLiftEvent(withLiftEvent: liftEvent, dataManager: dataManager)
initialViewController.viewModel = viewModel
initialViewController.dataManager = dataManager
self.window?.makeKeyAndVisible()

}
}

不幸的是,我确定 CalculatorLiftEventViewModelFromLiftEvent 对象永远不会被释放,这告诉我我有一个不会释放的强引用循环:

enter image description here

这肯定是另一个SO问题。

关于swift - 为什么旧 View 模型会响应通知?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48230283/

27 4 0
文章推荐: javascript - 根据里面的<iframe>改变
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com