肇鑫的技术博客

业精于勤,荒于嬉

Strongly Recommend You to Add Your Own UINavigationControllers even in iOS 14 when Using UISplitViewController

In iOS 14, Apple adapts UISplitViewController from two columns to three columns. Especially, it says that

If you set a child view controller that’s not a navigation controller, the split view controller creates a navigation controller for it.

However, Apple didn't say that it will try to reuse the UINavigationController when you reset the columns.

That means, when you set .secondary view controller to another view controller, the split view controller will push the new view controller to the back stack, which is not what you want.

Issue Sample

UISplitViewController Issue

  1. run the sample
  2. you will see detail 01, press back
  3. you will see master 01, press back
  4. you will see primary, press Master 02
  5. you will see Master 02, press Master 02
  6. you will see Detail 02, press back

You expect to see Master 02.
You see Detail 01.

Work Around

Add a UINavigationViewController to each of detail view controllers.

UISplitViewController Issue work around

I have file this as a bug to Apple. The id is FB8640357.

Apple's Reply

Just got the reply from Apple. 8 days since I have filed this issue. Apple says:

After reviewing your feedback, we have some additional information for you:

This is expected behavior.

The secondary column gets this special treatment if the view controller gets set to a non-navigation controller when it already has a nav controller—i.e., it’s pushed onto the nav stack, as they discovered.

Expected use patterns would be:

• Change the contents of the detail view controller (not the vc itself) and send -showColumn:UISplitViewControllerColumnSecondary (if desired) to confirm that the secondary column is visible, or ...
• For the secondary column only, clear it first by setting its vc to nil, then setting new desired vc, or ...
• Manage the navigation controller in the secondary column directly with -setViewControllers: or push/pop. If you’re using an automatically created UINavigationController instead of one you provided, you can find it with -viewControllerForColumn: and then ask that vc for its navigation controller.

Apple gave 3 recommends. The first was easy to think of, but it needed the two view controllers to be very similar.

I like the second recommend most. func setViewController(_ vc: UIViewController?, for column: UISplitViewController.UISplitViewController.Column) does allow vc to be nil. And it is direct. There is some performance lose though. As it will create another UINavigationViewController each time.

The third recommend has the most performance. But it is indirect. And it smells bad. It should be seen as a workaround.

Final

I recommend to fix it in storyboard as I previously did. Or, using the second recommend by Apple.