Question

Here's how I set the associated object:

objc_setAssociatedObject(navigationItem, "rightButton", leftButtonView, OBJC_ASSOCIATION_RETAIN);

and here's how I get it:

UIButton *favoriteButton = (UIButton *)objc_getAssociatedObject(self.navigationItem, "rightButton");

The object is a UIButton in both instances, and I have the #import "objc/runtime.h" in both classes.

The thing is, it used to work, but now for some reason it returns null. Any ideas?

EDIT

I'm setting the associated object in another class by passing the navigationItem as an argument:

+ (void)setNavigationBarTitle:(NSString *)title 
                andLeftButton:(NSString *)leftButtonTitle 
                 withSelector:(SEL)leftSelector 
               andRightButton:(NSString *)rightButtonTitle 
                 withSelector:(SEL)rightSelector 
                    andTarget:(id)target 
            forNavigationItem:(UINavigationItem *)navigationItem;

I use this convenience method in my utility class to set up a navigation bar for each new view controller in my app. When creating the navigation bar buttons, I associate them with the navigation item - my first line of code in the question.

Was it helpful?

Solution 2

To quote a famous person:

Once you eliminate the impossible, whatever remains, no matter how improbable, must be the truth.

Since all the other guesses were wrong, the only other source of the problem that I can think of is that you are calling objc_removeAssociatedObjects() at some point. In your question you say that your code used to work, so we must assume that somewhere something changed, causing the execution path to suddenly take a different turn.

  • Possibility 1: The execution path now goes through that call to objc_removeAssociatedObjects() where before it didn't.
  • Possibility 2: You already called objc_removeAssociatedObjects() before, but now you are passing a different value to the function.

It's impossible to say which one of those two it is.

You say in your comment that you do not pass the navigationItem in question and ask for an explanation. Unfortunately I cannot provide one. With the knowledge I currently have, I must assume that either your claim or the Apple docs for the function are incorrect. Since objc_removeAssociatedObjects() has worked for me in the past, I naturally tend to believe Apple :-)

I might ask: How did you verify that you do not pass the wrong object to the function? My suggestion: Add two NSLog statements to the code, just before you call objc_getAssociatedObject() and objc_removeAssociatedObjects(), where you print the pointer of the object that you are passing to the two functions.

OTHER TIPS

This is a shot in the dark, because I could not reproduce the issue. The problem might be that the key argument of objc_set/getAssociatedObject() is a unique pointer.

So your code would not work if the two different classes use strings "rightButton" at different memory locations. The strings have the same contents, but the pointer is different.

In any case, you should ensure that the identical key is used for setting and retrieving the associated object:

  • In a common header file (or in the .pch file) put an extern declaration:

    extern const void *rightButtonKey;
    
  • In exactly one .m file define the variable. The "self-reference" guarantees that the pointer has a unique value:

    const void *rightButtonKey = &rightButtonKey;
    
  • Then use it like

    objc_setAssociatedObject(navigationItem, rightButtonKey, leftButtonView, OBJC_ASSOCIATION_RETAIN);
    

You use different keys: you set object for key "leftButton" and get for "rightButton".

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top