2

In iOS 10, I could determine the list of navigation bar buttons I want to appear in viewDidLoad, and they would appear in the navigation bar as the view controller transitioned in.

In iOS 11, I can no longer do this. Whatever navigation bar buttons were set in interface builder are displayed as the view controller transitions in, and my custom list of buttons are not displayed until after the view finishes sliding in. Updating the buttons in viewWillAppear does not help.

Is this simply a bug in iOS 11, or is there something else I should be doing? Is there a workaround so I can continue to display buttons while the screen loads?

In the following example, I have set a button "Default Button" in the storyboard, and override it with an "Edit" button in viewDidLoad. The project is available on Github.

iOS 10

iOS 10 Behavior

iOS 11

iOS 11 Behavior

Chris Vasselli
  • 13,064
  • 4
  • 46
  • 49
  • 1
    Have you checked this on real device? – Shubham Oct 11 '17 at 17:55
  • Good thought! But yes, I have verified that the same thing happens on a real device. – Chris Vasselli Oct 11 '17 at 20:29
  • Maybe a bug in the split view's detail nested navigation controller, when setting the navigation item properties for some reason don't cause the outermost navigation controller to redraw its navigation bar before the animation begins. – malhal Jan 12 '19 at 11:32
  • Loading the view in prepareForSegue in Chris Vasselli's code sample below is a good workaround. – malhal Jan 12 '19 at 11:37

2 Answers2

1

It looks like the issue is that navigation bar icons displayed during the transition appear to be fixed when the view controller is passed off to the navigation controller. By the time that viewDidLoad is called, the icons have already been fixed.

In order to fix this, we need to update the navigation bar icons on the view controller's navigationItem before the view controller is pushed onto the navigation controller stack.

One way to do this would be to setup the navigation bar icons in awakeFromNib. This is what @Joe's answer was effectively doing, because apparently viewDidLoad is called from awakeFromNib when isViewLoaded is true during awakeFromNib.

However, doing this in awakeFromNib prevents you from taking into account any properties set on the view controller in prepareForSegue. So another option (and the one that I am using) is to force the entire view to load in prepareForSegue by adding the line _ = controller.view after setting any desired properties.

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "showDetail" {
        if let indexPath = tableView.indexPathForSelectedRow {
            let controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController
            ...
            _ = controller.view
        }
    }
}
Chris Vasselli
  • 13,064
  • 4
  • 46
  • 49
-1

Move your Edit barButton code from viewDidLoad to isViewLoaded method as below.

  override var isViewLoaded: Bool {
    self.navigationItem.rightBarButtonItem = self.editButtonItem
    return true
  }

Output:

enter image description here

Note: Above code will fix the transition delay issue. Really, don't have much to explain why this happening. I experienced similar issue in iOS 10 as well NavigationBar delay updating barTintColor iOS10. It could be another bug in iOS11.


PS:

After reading Apple Doc about isViewLoaded and comparing other view loading methods. Its all about loading memory upon view loads.

You don't really need to move you barButton code at all.Just implement the isViewLoaded method and return to true as below:

override var isViewLoaded: Bool { return true}
Joe
  • 8,868
  • 8
  • 37
  • 59
  • Hmm, very interesting that this works. But overriding `isViewLoaded` to always return true doesn't really seem like a good solution, since it will return `true` when we _haven't_ actually loaded the view yet. And the result of `isViewLoaded` could be used elsewhere, and so overriding it could break something else. – Chris Vasselli Oct 11 '17 at 20:31
  • Did you look at the link (fixed)posted on PS. Apple Doc mentioned clearly `The value of this property is true when the view is in memory or false when it is not`. – Joe Oct 11 '17 at 20:46
  • Right. So, by overriding this property we are breaking that behavior, because now the property will be true even before the view is loaded into memory. – Chris Vasselli Oct 11 '17 at 20:48
  • Memory allocation only happen when the view loads. If you wanna go more into it .run a memory test.see is that make any diffrence. – Joe Oct 11 '17 at 21:06