@implementation UINavigationBar (BackButtonDisplayFix)
if ([UIDevice currentDevice].systemVersion.intValue >= 7)
* We first try to simply add an override version of didAddSubview: to the class. If it
* fails, that means that the class already has its own override implementation of the method
* (which we are expecting in this case), so use a method-swap version instead.
Method didAddMethod = class_getInstanceMethod(self, @selector(_displaybugfixsuper_didAddSubview:));
if (!class_addMethod(self, @selector(didAddSubview:),
Method existMethod = class_getInstanceMethod(self, @selector(didAddSubview:));
Method replacement = class_getInstanceMethod(self, @selector(_displaybugfix_didAddSubview:));
- (void)_displaybugfixsuper_didAddSubview:(UIView *)subview
- (void)_displaybugfix_didAddSubview:(UIView *)subview
[self _displaybugfix_didAddSubview:subview]; // calls the existing method
Additional note: This bug appears to be fixed in iOS 7.1. So, the patch could be conditionalized to only install the methods if running >= 7.0 and < 7.1.
As mentioned, ideally you would be able to change to a borderless look on iOS7, which means that the bug isn't really apparent (since there is no background image). For some iOS6/iOS7 transition situations though, that may be difficult (lots of screens, and/or the need to support older iOS versions for a while and too hard to have two looks implemented, and it doesn't look good borderless without other changes). If that's the case, the following patch should work:
Note: UINavigationBar does currently have an override of the method in question, so I'd expect the method_exchangeImplementations style to be used. I just added the other stuff for safety in case Apple changes their code. We may go borderless ourselves, but I did find this approach worked as an option (until a more thorough UI uplift), at least.
Thanks! I use this by subclassing the UINavigationBar and overriding the didAddSubview.
The custom background image not appearing initially was not fixed in iOS7 GM or final, as far as I can tell. I see the same problem. It does seem to be an Apple bug; the private view Apple uses simply does not get a setNeedsDisplay call when it needs it on initial display. Doing anything to it which causes that call should fix it -- like pressing on it (which likely changes internal state so it calls setNeedsDisplay on itself), or bringing a modal up (which probably forces a redisplay of the entire view hierarchy on the next viewWillAppear: call).
Using leftBarItems instead also can work, but that may cause a lot of maintenance issues with existing code (some screens may have their own left items, expecting that when set back to nil they restore the original back item, for example).