【问题标题】:Why are not my subscriptions not disposed even though disposebag is hooked and my view is dismissed?为什么即使 disposebag 被钩住并且我的视图被驳回,我的订阅也没有被处理?
【发布时间】:2022-06-14 17:39:38
【问题描述】:

我最近注意到我的subscriptions 实际上都不是disposed,即使我钩了.disposed(by: disposeBag)。即使我完全离开viewdismissmodalsubscriptions 也拒绝dispose

我在tabBar 中有我的views,我想它可以让subscriptions 保持活力,即使我离开了view,但即便如此,这个tabBarmodal 中,当modaldismissed 不应该是 subscriptions dispose 自己?

解决此问题的一种方法是在viewWillDisappear 上手动dispose all subscriptions,但我仍然想知道为什么这个问题仍然存在。

private func noErrorText() {
    viewModel.activeErrorContent.debug("--debugNoErrorText").subscribe(onNext: { [weak self] cells in
        self?.noErrorView.isHidden = !cells.isEmpty 
    }).disposed(by: disposeBag)
}

它给出了输出:

2022-03-25 04:26:55.219: --debugNoErrorText -> 已订阅 2022-03-25 04:26:55.219:--debugNoErrorText -> 事件下一个([])

如果还有什么需要我提供或解释的,请告诉我。

编辑 回应 cmets:

disposeBag 在superClass 中,而我的subscriptionsdisposed(by:)subClass 中。不确定这是否相关。

final class TechnicianDashboardViewController: BaseViewController {...

这是我的subscriptions

如果我对 strong 引用的理解正确,那么第一个 sn-p 中的 self.disposeBag 会创建对 subView 的强引用。

extension TechnicianDashboardViewController: PinCodeViewControllerDelegate, UITableViewDelegate {
    func completed(currentPin: String?, newPin: String) {
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
            guard let self = self else { return }
            self.resetWithOverlay(pin: newPin)
                .subscribe().disposed(by: self.disposeBag)
        }
    }
}

还有这些。都使用相同的disposeBag。他们都不是disposed

private func noErrorText() {
        viewModel.activeErrorContent.subscribe(onNext: { [weak self] cells in
            self?.noErrorView.isHidden = !cells.isEmpty
        }).disposed(by: disposeBag)
    }
    
private func getErrors() {
    viewModel.activeErrorContent.bind(to: activeErrorTableView.rx
                                            .items(cellIdentifier: ErrorsTableViewCell.identifier,
                                                   cellType: ErrorsTableViewCell.self)) { row, data, cell in
                                                       cell.rowService = row
                                                       cell.viewModel = data
    }.disposed(by: disposeBag)
}
    
private func getEvents() {
    viewModel.activeEventContent.bind(to: activeEventTableView.rx
                                            .items(cellIdentifier: EventStatusTableViewCell.identifier,
                                                   cellType: EventStatusTableViewCell.self)) { row, data, cell in
                                                       cell.viewModel = data
                                                       cell.rowService = row
    }.disposed(by: disposeBag)
}

【问题讨论】:

  • 当对 dispose bag 有强引用的对象 deinit 时,dispose bag 释放订阅。哪些对象对您的处理包有很强的引用?
  • @DanielT。喔好吧。当您说“强烈引用 disposebag 的对象”时,您是指所有使用 .disposed(by: disposeBag) 的订阅吗?或者我如何知道哪些对象具有强引用?有没有办法检查?你能详细说明一下吗? :)
  • disposeBag 是某个类的属性。也许您将它传递给其他对象?不,.disposed(by: disposeBag) 不会创建强引用。
  • 不,这将是一个可怕的想法。显示代码或回答我的问题。哪些对象对您的处理包有很强的引用?
  • 不,这不会产生强引用。根据您到目前为止显示的内容(假设您显示的所有代码都在视图控制器中),当TechnicianDashboardViewController deinits 时,所有订阅都将被释放。您的视图控制器是否正在取消初始化?

标签: ios swift rx-swift dispose


【解决方案1】:

所以我找到了subscriptions 不处理的原因和解决方案,非常感谢@Daniel T。我会在这里写下答案,以防有人遇到类似问题。

所以基本上我在deinit 中添加了一个print,如下所示:

deinit {
    print("-- DEINIT")
}

事实证明,它根本没有被触发(嗯,它们在加载任何东西之前就在开始时被触发,但当你退出 view 时不会触发,我认为这是因为 viewstabBar controller,但这是另一个话题)。这适用于几个views。这意味着subscriptions 不是disposed,因为这发生在deinit

那么下一个问题是,为什么没有触发deinit。那是因为有一个memory leak 阻止ARC 释放对view 的引用。内存泄漏可能是由不同的原因引起的,但大多数情况下是因为您忘记将[weak self] 添加到闭包中。如果您只是在一个地方忘记它,您可以阻止deinit 触发。就我而言,我的错误经常被“隐藏”在super class 中,使其不那么明显。

因此,修复memory leak 以使deinit 触发器,然后将dispose 您的subscriptions 像平常一样,防止进一步memory leaks

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-12-26
    • 2020-01-03
    • 2011-07-11
    • 1970-01-01
    • 2011-02-15
    • 2019-09-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多