Доступ к частной переменной в категории приводит к ошибке компоновщика

EDIT: Я не собираюсь этого делать, теперь я понимаю, насколько это опасно. Но вопрос остается в чисто академических целях.

Я пытаюсь реализовать категорию в NSCollectionView, которая позволит мне получить доступ к частной переменной _displayedItems. Мне нужно иметь доступ к нему в моем подклассе. Итак, я создал следующую категорию:

@interface NSCollectionView (displayedItems)

- (NSMutableArray *)displayedItems;

@end


@implementation NSCollectionView (displayedItems)

- (NSMutableArray *)displayedItems
{
    return _displayedItems;
}

@end

... Кажется, что он отлично работает. Однако, когда я пытаюсь скомпилировать это, компоновщик дает мне следующую ошибку:

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

Я знаю, что _displayedItems существует в NSCollectionView, я просмотрел интерфейс, а также распечатал его содержимое с помощью gdb. Кто-нибудь знает, как это исправить?

Спасибо заранее! Билли

Ответ 1

_displayedItems - частный ivar, поэтому вы не должны обращаться к нему, даже из категории.

Тем не менее, вы должны попробовать скомпилировать тот же код с помощью

gcc -arch i386

и

gcc -arch x86_64

и увидеть разницу. В 32-битном режиме вы не видите ошибку. Это показывает, насколько хрупкой ситуация. Вы действительно не должны.

Тем не менее, есть способ получить этот ivar, злоупотребляя KVC:

@implementation NSCollectionView (displayedItems)

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

@end

Обратите внимание, что вы не должны называть свой метод так же, как displayedItems. Это сделало бы бесконечный цикл, потому что техника KVC нашла бы ваш метод раньше, чем ivar. См. здесь.

Или вы можете получить доступ к любому скрытому ivar, используя Objective-C функции времени исполнения. Это также весело.

Однако позвольте мне еще раз сказать. Там большая разница в знании, что вы можете сделать одно и сделать это по-настоящему. Подумайте о каком-нибудь отвратительном преступлении. и делать это самостоятельно.

НЕ ДЕЛАЙТЕ ЭТО!!!!!

Ответ 2

Вы не должны на самом деле, но обращайтесь к нему как указатель на член структуры:

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

Это хрупкая вещь, которая, как я уверен, вы знаете, но;)

UPDATE: поскольку вы упомянули выше, не работает, попробуйте отказаться от выполнения:

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

(Протестировано, работает)