I have several UIViewController
s which are added to a content view. After calling my remove function, I'm noticing that the child UIViewController
's deinit
function is not being called unless I explicitly set the value of the child UIViewController
to nil
.
Is that the proper behavior or am I doing something wrong?
func removeViewController(fromCell cell:UICollectionViewCell, at indexPath:IndexPath){
guard let childViewController = currentViewControllers[indexPath] else { return }
print("remove view controller called")
childViewController.willMove(toParent: nil)
childViewController.view.removeFromSuperview()
childViewController.removeFromParent()
currentViewControllers[indexPath] = nil
// recycledViewControllers.insert(childViewController)
}
The problem is that you have two references to the child view controller:
The reference maintained automatically by the parent view controller (childViewControllers
, or children
in modern Swift)
An additional reference that you yourself have added (currentViewControllers
).
You therefore have to let both of them go before the child view controller can go out of existence. That is what your code does:
childViewController.willMove(toParent: nil)
childViewController.view.removeFromSuperview()
childViewController.removeFromParent()
// now `childViewControllers` / `children` has let go
currentViewControllers[indexPath] = nil
// now `currentViewController` has let go
So you're not doing anything wrong, per se, except insofar as you've added this extra strong reference by having this currentViewControllers
in the first place. But I can see why you've done that: you want a way to pair index paths with child view controllers.
So you can live with your approach just fine, or if you really want to you can rig currentViewControllers
to have only weak references to its values (by using NSMapTable instead of a dictionary).