Search code examples
iosswiftuiviewcontrollerautomatic-ref-countingdeinit

How do I deinitialize a child UIViewController?


I have several UIViewControllers 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)
} 

Solution

  • 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).