I'm trying to test some animations between UIViewControllers
and in this particular case I have a UIViewController
that adds another UIVC
as its child view.
Everything works as expected, the child view gets added and presented, then on the child view I have a UINavigationBar
which has a cancel button (dismiss) as its left bar button.
When I click on that button, I fire a function which tries to remove this presented child view, from the view hierarchy (from its parent view).
Code from the parent view:
// 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)
}
As you see above, when I click the present button, it instantiates the child view and animates it in, so far so good.
Child View code:
// ChildViewController -> Child (ofc)
@objc func didTapCancel() {
self.willMove(toParentViewController: nil)
self.view.removeFromSuperview()
self.removeFromParentViewController()
}
Now on the child view, when I click the cancel button, I know I have to call the removeFromParentViewController()
in order to it be properly removed, but the app crashes if I do that with the followingg error:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[dismissLayerTest.ChildViewController name]: unrecognized selector sent to instance 0x7fea2f60a920'
Then I tried to comment the self.removeFromParentViewController()
line, and by doing so, the app doesn't crash, but then on the parent view controller I can see that the view is still attached to its parent by printing self.childViewControllers.count
and it shows me 1
.
Can you see where the problem is ?
Thanks
I figure out where the problem was.
After some tests, I discovered that we should not use lazy
instantiations while using parent-child View Controllers
.
Since the I instantiated the childViewController
as lazy
when I tried to remove it from the parentViewController
the error said unrecognized selector sent to instance
so I found out that the property pointer-selector was somehow deallocated on the parentViewController
which didn't knew what child it was to dismiss, because it lost its reference.
In order to fix it, I removed the lazy
instantiation, so it remains always in scope and now I can successfully remove the child from its parent scope.
var childViewController: ChildViewController = {
let viewController = ChildViewController()
return viewController
}()