PopViewController strange behaviour

前端 未结 5 946
忘掉有多难
忘掉有多难 2021-01-20 03:01

Due to a weird request which I tried to turn down but it didn\'t work, I had to override the navigationBar\'s back Button.

I have made a custom UINavigationControlle

5条回答
  •  臣服心动
    2021-01-20 03:39

    (My previous post was completely wrong. This is a complete rewrite with an appropriate solution.)

    I had this behavior pop up when I chose to delete some code generating a warning when I was converting to ARC -- code that I thought was not being called.

    Here's the situation:

    If you shadow navigationBar:shouldPopItem: in a subclass of UINavigationController, then the current view controller will NOT be popped when the user touches the NavBar's BACK button. However, if you call popViewControllerAnimated: directly, your navigationBar:shouldPopItem: will still be called, and the view controller will pop.

    Here's why the view controller fails to pop when the user touches the BACK button:

    UINavigationController has a hidden method called navigationBar:shouldPopItem:. This method IS called when the user clicks the BACK button, and it is the method that normally calls popViewControllerAnimated: when the user touches the BACK button.

    When you shadow navigationBar:shouldPopItem:, the super class' implementation is not called, and hence the ViewController is not popped.

    Why you should NOT call popViewControllerAnimated: within your subclass' navigationBar:shouldPopItem::

    If you call popViewControllerAnimated: within navigationBar:shouldPopItem:, you will see the behavior that you desire when you click the BACK button on the NavBar: You can determine whether or not you want to pop, and your view controller pops if you want it to.

    But, if you call popViewControllerAnimated: directly, you will end up popping two view controllers: One from your direct call to popViewControllerAnimated:, and one from the call you added to within navigationBar:shouldPopItem:.

    What I believe to be the safe solution:

    Your custom nav controller should be declared like this:

    @interface CustomNavigationController : UINavigationController  
    {
        // .. any ivars you want
    }
    @end
    

    Your implementation should contain code that looks something like this:

    // Required to prevent a warning for the call [super navigationBar:navigationBar shouldPopItem:item]
    @interface UINavigationController () 
    @end
    
    
    @implementation CustomNavigationController
    
    - (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item
    {
        BOOL rv = TRUE;
    
        if ( /* some condition to determine should NOT pop */ )
        {
            // we won't pop
            rv = FALSE;
    
            // extra code you might want to execute ...
        } else
        {
            // It's not documented that the super implements this method, so we're being safe
            if ([[CustomNavigationController superclass]
                    instancesRespondToSelector:@selector(navigationBar:shouldPopItem:)])
            {
                // Allow the super class to do its thing, which includes popping the view controller 
                rv = [super navigationBar:navigationBar shouldPopItem:item];
    
            }
        }
    
        return rv;
    }
    

提交回复
热议问题