10

EDIT: I'm not going to do this, I now realize how dangerous this can be. But, the question stays for purely academic purposes.

I'm trying to implement a category on NSCollectionView that will let me access the private variable _displayedItems. I need to be able to access it in my subclass. So, I've created the following category:

@interface NSCollectionView (displayedItems)

- (NSMutableArray *)displayedItems;

@end


@implementation NSCollectionView (displayedItems)

- (NSMutableArray *)displayedItems
{
    return _displayedItems;
}

@end

...which seems like it should work perfectly. However, when I try to compile this, the linker gives me the following error:

Undefined symbols:
  "_OBJC_IVAR_$_NSCollectionView._displayedItems", referenced from:
      -[NSCollectionView(displayedItems) displayedItems] in NSCollectionView+displayedItems.o
ld: symbol(s) not found
collect2: ld returned 1 exit status

I know for a fact that _displayedItems exists in NSCollectionView, I've looked at the interface and also printed it's contents using gdb. Does anyone know of a way to fix this?

Thanks in advance!
Billy

vilhalmer
  • 1,149
  • 3
  • 11
  • 23
  • I found this to be the best answer. Easy, simple and safe: http://stackoverflow.com/questions/16678463/accessing-a-method-in-a-super-class-when-its-not-exposed – Khurram Ali Jun 06 '14 at 10:28

2 Answers2

12

_displayedItems is a private ivar, so you shouldn't access it, even from a category.

That said, you should try compiling the same code with

gcc -arch i386

and

gcc -arch x86_64

and see the difference. In the 32 bit mode you don't see the error. This shows how fragile the situation is. You really shouldn't.

That said, there's a way to get that ivar by abusing KVC:

@implementation NSCollectionView (displayedItems)

- (NSMutableArray *)myDisplayedItems
{
    return [self valueForKey:@"displayedItems"];
}

@end

Note that you shouldn't name your method just as displayedItems. That would make an infinite loop, because the KVC machinery would find your method earlier than the ivar. See here.

Or you can access any hidden ivar using Objective-C runtime functions. That's also fun.

However, let me say again. There's a big difference in knowing you can do one thing and doing that thing for real. Just think of any hideous crime. and doing that by yourself.

DON'T DO THAT!!!!!

Community
  • 1
  • 1
Yuji
  • 34,103
  • 3
  • 70
  • 88
  • 1
    I'd move the "don't do that" to the top. :) If you start mucking about with the internal state of framework classes, you are sure to be surprised by crashes and mysterious failures over time. – bbum Dec 13 '10 at 18:14
  • @bbum isn't the `object_getInstanceVariable` suggested in the other answer relatively innocuous? – Dan Rosenstark Nov 20 '13 at 17:39
  • You are hanging state off objects whose internal implementation details may change. Consider NSNumber whose values may be singletons and that changes per platform. Injecting stats into the middle system classes is bad design. @yar – bbum Nov 20 '13 at 18:28
  • thanks @bbum, true, it breaks encapsulation, thanks for responding. – Dan Rosenstark Nov 20 '13 at 19:55
5

You shouldn't really, but access it like a pointer to a member of a struct:

-(NSMutableArray *)displayedItems {
  return self->_displayedItems;
}

This is a fragile thing to do, as I'm sure you're aware however ;)

UPDATE: Since you've mentioned the above doesn't work, try dropping down to the runtime:

-(NSMutableArray *)displayedItems {
        NSMutableArray *displayedItems;
        object_getInstanceVariable(self, "_displayedItems", (void *)&displayedItems);
        return displayedItems;
}

(Tested, works)

d11wtq
  • 34,788
  • 19
  • 120
  • 195
  • This doesn't work either, it gives an identical error. Thanks for the suggestion, though! – vilhalmer Dec 13 '10 at 13:48
  • 3
    That's a technically correct answer, but not a morally correct answer :p – Yuji Dec 13 '10 at 14:07
  • Yeah, I figured the OP had already made the decision to ignore any concerns about fragility based on the nature of the question, but I agree with you 100% :) – d11wtq Dec 13 '10 at 14:10
  • This does indeed work, but I've decided to listen to the pleas not to do this, and devised another method of getting at the info that doesn't require anything immoral. :) Thanks anyway! – vilhalmer Dec 15 '10 at 11:29