Search code examples
iphoneobjective-cprivateuinavigationitem

how to access @private variable _navigationBar in the UINavigationItem class


UINavigationItem has the following private variables

UIKIT_EXTERN_CLASS @interface UINavigationItem : NSObject <NSCoding> {

@private
 NSString        *_title;
 NSString        *_backButtonTitle;
 UIBarButtonItem *_backBarButtonItem;
 NSString        *_prompt;
 NSInteger        _tag;
 id               _context;
 UINavigationBar *_navigationBar;
 UIView          *_defaultTitleView;
 UIView          *_titleView;
 UIView          *_backButtonView;
 UIBarButtonItem *_leftBarButtonItem;
 UIBarButtonItem *_rightBarButtonItem;
 UIView          *_customLeftView;
 UIView          *_customRightView;
 BOOL             _hidesBackButton;
 UIImageView     *_frozenTitleView;

}

Is there any way (using KVC,etc.) to read the UINavigationBar *_navigationBar; I need this to get access to the undefined backButton. which is not in:

@property(nonatomic,retain) UIBarButtonItem *leftBarButtonItem; @property(nonatomic,retain) UIBarButtonItem *backBarButtonItem;


Solution

  • Don't do this. It violates the fundamental OOP concept of encapsulation. If Apple decides to rearrange the order or meaning of the ivars in the UINavigationItem class, your code may break unpredictably up to and including crashes or man-eating purple dragons.


    That said, if you're sure you want to go down this evil evil road, you should be able to reach the _navigationBar ivar with:

    UINavigationItem *theItem = ...;
    UINavigationBar *bar = [theItem valueForKey: @"_navigationBar"];
    

    If that doesn't work (for instance, if Apple has overridden +accessInstanceVariablesDirectly on this class), you can drop down to the Objective-C runtime:

    #include <objc/runtime.h>
    
    UINavigationItem *theItem = ...;
    UINavigationBar *bar = nil;
    Ivar barIvar = class_getInstanceVariable([UINavigationItem class], "_navigationItem");
    if (barIvar) {
        bar = *(UINavigationBar *)((void *)theItem + ivar_getOffset(barIvar));
    }
    

    Both approaches are incredibly dangerous and run the risk of breaking with any and every point release of the operating system. You have been warned. Here be dragons.