2

我有一个MainViewController由 ViewModel(称为)支持的 ViewController(称为MainViewModel)。

ViewModel 有一个变量,它定义了哪个子 ViewControllerMainViewController应该作为其子级呈现。

我的问题是,当一个孩子被移走以支持另一个孩子时,它永远不会被deinit教育。

这是代码:

主视图控制器:

class MainViewController: UIViewController {

    var viewModel: MainViewModel!
    private let disposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()

        viewModel.viewController
            .subscribe(onNext: { [weak self] vc in
                self?.newVc(vc)
            })
            .disposed(by: disposeBag)
    }

    static func instantiate(viewModel: MainViewModel) -> MainViewController {
        let vc = MainViewController()
        vc.viewModel = viewModel
        return vc
    }

    private func newVc(_ vc: UIViewController) {
        remove(childViewController: children.first)
        addFullScreen(childViewController: vc)
    }
}

主视图模型:

class MainViewModel {

    lazy var viewController: Observable<UIViewController> = {
        return Observable.just(ColorViewController(.green))
            .delay(RxTimeInterval.seconds(3), scheduler: MainScheduler.instance)
            .startWith(ColorViewController(.yellow))
    }()

}

您在MainViewModelsviewController变量中看到,它首先发出一个黄色的 ColorViewController,3 秒后发出一个绿色的。 ColorViewController是 UIViewController 的基本子类,具有彩色视图,并deinit覆盖了 - 方法。当黄色的 ColorViewController 被移除时,这个方法不会被调用。

谁拥有对那个黄色 ColorViewController 的引用,以及如何修复它?

奖金代码:

extension UIViewController {

    public func addFullScreen(childViewController child: UIViewController) {
        guard child.parent == nil else { return }

        addChild(child)
        view.addSubview(child.view)

        child.view.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            view.leadingAnchor.constraint(equalTo: child.view.leadingAnchor),
            view.trailingAnchor.constraint(equalTo: child.view.trailingAnchor),
            view.topAnchor.constraint(equalTo: child.view.topAnchor),
            view.bottomAnchor.constraint(equalTo: child.view.bottomAnchor)
        ])

        child.didMove(toParent: self)
    }

    public func remove(childViewController child: UIViewController?) {
        guard let child = child else { return }
        guard child.parent != nil else { return }

        child.willMove(toParent: nil)
        child.view.removeFromSuperview()
        child.removeFromParent()
    }
}

更新:

所以我将viewController-variable 更改为:

lazy var viewController: Observable<UIViewController> = {
        return Observable<Int>.interval(RxTimeInterval.seconds(3), scheduler: MainScheduler.instance)
            .scan(0, accumulator: { (prev, next) -> Int in return prev + 1 })
            .map { index -> UIViewController in
                let modul = index % 3
                print("Index: \(index): \(modul)")
                switch modul {
                case 0: return ColorViewController(.yellow, tag: "Yellow")
                case 1: return ColorViewController(.blue, tag: "Blue")
                case 2: return ColorViewController(.green, tag: "Green")
                default: return ColorViewController(.red, tag: "Red")
                }
            }.startWith(ColorViewController(.cyan, tag: "Initial 1"),
                        ColorViewController(.purple, tag: "Initial 2"))
            .take(10)
    }()

现在我看到所有ColorViewController生成的 '.map都按预期取消初始化。但是这两个传入.startWith, 永远不会被取消初始化,即使在.take(10)导致 Observable 完成之后也是如此。这对任何人都有意义吗?

4

1 回答 1

1

打开可视内存调试器,找出谁在持有您想要释放的视图控制器。这是一篇关于它的文章:https ://useyourloaf.com/blog/xcode-visual-memory-debugger/

以及来自 Apple 的视频:https ://developer.apple.com/videos/play/wwdc2018/416

于 2019-08-28T00:28:32.263 回答