Swift 4.0、Xcode 9.2下DetailViewController中UIBarButton缺失求助
Hey there, let's break down why your "Item" UIBarButton is vanishing when you run your app, even though it shows up perfectly in Storyboard. Based on the steps you outlined (using Swift 4.0, Xcode 9.2, Master-Detail app with a TabBarController embedded in the detail view), this is almost certainly a navigation hierarchy issue.
What's Going On?
Here's the core problem: When you embed a TabBarController into your DetailViewController and then add the UIBarButton to the first tab's view controller, that tab's view controller doesn't have a proper connection to a navigation bar.
The original DetailViewController lives inside a NavigationController, but that navigation bar belongs to the parent DetailViewController—not the child view controllers inside the TabBarController. So when you drag the button into the tab's view in Storyboard, Xcode lets you place it, but at runtime, there's no actual navigation bar tied to that tab's view controller to display it.
Fixes to Try
Option 1: Wrap Each Tab's View Controller in Its Own Navigation Controller (Recommended)
This is the cleanest, most standard approach for tab-based interfaces:
- Select the view controller for your first tab in Storyboard
- Right-click it and choose Embed In > Navigation Controller
- Repeat this for any other tab view controllers that need a navigation bar
- Now, when you drag the UIBarButton into the first tab's navigation bar, it'll show up reliably at runtime
Option 2: Control the Button via the Parent DetailViewController (Quick Fix)
If you don't want to add separate Navigation Controllers for each tab, you can add the button directly to the DetailViewController's navigation bar and toggle its visibility based on the selected tab:
- In Storyboard, drag the UIBarButton into the DetailViewController's navigation bar (not the tab's view controller)
- Add this code to your
DetailViewController.swiftto show/hide the button when the tab changes:
override func viewDidLoad() { super.viewDidLoad() // Hook into the TabBarController's delegate if let tabBarController = childViewControllers.first as? UITabBarController { tabBarController.delegate = self // Hide the button initially if needed navigationItem.rightBarButtonItem?.isHidden = (tabBarController.selectedIndex != 0) } } // MARK: - UITabBarControllerDelegate extension DetailViewController: UITabBarControllerDelegate { func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) { // Only show the button when the first tab is selected navigationItem.rightBarButtonItem?.isHidden = (tabBarController.selectedIndex != 0) } }
Quick Checks to Rule Out Other Issues
- Double-check that you have a valid way to navigate to the DetailViewController after deleting the original segue (e.g., a programmatic
pushViewControllercall from MasterViewController) - Make sure none of your tab view controllers have "Is Initial View Controller" checked—this can mess up the navigation stack
- Try cleaning your build folder (
Command + Shift + K) and re-running the app, since Xcode 9.2 sometimes has Storyboard caching quirks
内容的提问来源于stack exchange,提问作者muthyas

