从父级移除子视图控制器时应用程序崩溃

App crashes when removing child view controller from its parent

我正在尝试测试 UIViewControllers 之间的一些动画,在这种特殊情况下,我有一个 UIViewController 添加另一个 UIVC 作为其子视图。

一切都按预期工作,添加并显示了子视图,然后在子视图上我有一个 UINavigationBar,它的左栏按钮有一个取消按钮(关闭)。

当我点击那个按钮时,我触发了一个函数,它试图从视图层次结构(从它的父视图)中删除这个呈现的子视图。

来自父视图的代码:

    // ViewController -> Parent

lazy var presentButton: UIButton = {
    let b = UIButton(type: .custom)
    b.setTitle("Present", for: .normal)
    b.setTitleColor(.black, for: .normal)
    b.addTarget(self, action: #selector(didTapPresentButton), for: .touchUpInside)
    return b
}()

lazy var childViewController: PresentedViewController = {
    let viewController = PresentedViewController()
    return viewController
}()


@objc func didTapPresentButton() {
    addViewControllerAsChildViewController(childViewController: childViewController)    
}


func addViewControllerAsChildViewController(childViewController: UIViewController) {
    self.addChildViewController(childViewController)
    childViewController.view.frame = CGRect.zero

    self.view.addSubview(childViewController.view)

    let newFrame = view.bounds
    UIView.animate(withDuration: 2) {
        childViewController.view.frame = newFrame
    }
    childViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    childViewController.didMove(toParentViewController: self)
}

正如您在上面看到的,当我单击当前按钮时,它会实例化子视图并将其动画化,到目前为止一切顺利。

子视图代码:

// ChildViewController -> Child (ofc)

@objc func didTapCancel() {
    self.willMove(toParentViewController: nil)
    self.view.removeFromSuperview()
    self.removeFromParentViewController()
}

现在在子视图上,当我单击取消按钮时,我知道我必须调用 removeFromParentViewController() 才能正确删除它,但是如果我这样做应用程序会崩溃并出现以下错误:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[dismissLayerTest.ChildViewController name]: unrecognized selector sent to instance 0x7fea2f60a920'

然后我尝试评论 self.removeFromParentViewController() 行,这样做,应用程序不会崩溃,但是在父视图控制器上我可以看到视图仍然附加到它的父视图打印 self.childViewControllers.count 并显示 1.

你能看出问题出在哪里吗?

谢谢

我找出问题所在了。

经过一些测试,我发现我们不应该在使用parent-child View Controllers时使用lazy实例化。

因为我将 childViewController 实例化为 lazy 当我试图将其从 parentViewController 中删除时,错误显示 unrecognized selector sent to instance 所以我发现 属性 pointer-selector 以某种方式在 parentViewController 上被释放,它不知道 child 它要解雇什么,因为它失去了它的引用。

为了修复它,我删除了 lazy 实例化,因此它始终保留在范围内,现在我可以从其 parent 范围中成功删除 child。

var childViewController: ChildViewController = {
    let viewController = ChildViewController()
    return viewController
}()