从父级移除子视图控制器时应用程序崩溃
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
}()
我正在尝试测试 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
}()