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

ViewModel有一个变量,该变量定义应将哪个子级ViewController MainViewController呈现为其子级。

我的问题是,当删除一个孩子而又另一个孩子时,它永远不会得到deinit

这是代码:

MainViewController:

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)
    }
}

MainViewModel:
class MainViewModel {

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

}

您在MainViewModelviewController变量中看到,它首先发出黄色的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完成之后也是如此。这对任何人有意义吗?

最佳答案

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

还有苹果的视频:https://developer.apple.com/videos/play/wwdc2018/416

08-05 23:39