iOS 15 More Tab Crash

Hello,

The app I'm working on crashes by trying to reference a deallocated object. The object is a subclass of UITabBarController, and this crash only happens when there are enough view controllers in the tab bar that the more tab becomes available.

When turning on zombies, this is the message that gets printed: *** -[UITabBarControllerSubClass removeChildViewController:]: message sent to deallocated instance 0x7fefa98b2a00

In order for the crash to happen, the user has to perform an action that re-initializes the tab bar, such as logging out. This crash does not happen in iOS 14.

Does anyone know what might be happening here?

Hi aotondo,

we are experiencing the same issue as you described in our app. Did you find any fixes or workarounds? Thanks.

I can reproduce this one if I hold a strong reference to the UITabBarController subclass before I push it onto the navigation stack. The reference gets overwritten the next time I do it, the controller gets deallocated and I get the crash (with zombies enabled). There's no real reason for this to be strong, so I changed it to weak and it seems to resolve the problem.

This seems to be a timing issue and releasing the reference earlier resolves it in the simplest state. It's possible you have a reference somewhere else (perhaps in a block that's delaying the dealloc and causing your problem).

Did anyone find some other solutions? I tried all and nothing works, fixed also some memory leaks i had. In my project it happens randomly, sometimes the first time i do logout, sometimes i need to repeat the process 10-20 times in a row. I made also a minimal demo project with a nav controller that pushes the tab bar controller and at logout it pops to root, like the setup of my real app, but i can't make it crash.

After weeks of struggling i decided to get rid of the native More screen and made one myself. It was needing anyway some customizations that were a pain to do the native way.

Any luck finding a resolve @aotondo?

I solved this by explicitly removing the child view controllers before deallocating the UITabBarController:

window.rootViewController?.children.forEach { $0.removeFromParent() }
window.rootViewController = MyNewRootView()

The issue appears to be with how the UIMoreListController improperly retains the child view controllers until after UITabBarController finishes its dealloc, and then when those child view controllers go to dealloc they crash on a now-invalid (unowned?) reference to the UITabBarController as their parent view controller.

This only seems to occur when the UIMoreNavigationController is set as the UITabBarController's _selectedViewController ivar. Unfortunately, it's not easy to detect if that's the case, because the getter for selectedViewController will (contrary to what is said in the header comments) return whichever of the UITabBarController's viewControllers children is shown in the UIMoreNavigationController, NOT the UIMoreNavigationController reference directly.

I was able to workaround this issue by always running

tabBarController.selectedViewController = tabBarController.viewControllers.firstObject;

to switch back to the first tab's (i.e. not under "More") controller immediately before triggering the deallocation of the UITabBarController. (In my case, the UITabBarController is already offscreen at this point, so there's no visual artifact from this last-moment switching.)

iOS 15 More Tab Crash
 
 
Q