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

РЕДАКТИРОВАТЬ: Я не собираюсь этого делать, теперь я понимаю, насколько это может быть опасно. Но вопрос остается в чисто академических целях.

Я пытаюсь реализовать категорию в 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

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

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

2 ответа

Решение

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

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

gcc -arch i386

а также

gcc -arch x86_64

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

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

@implementation NSCollectionView (displayedItems)

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

@end

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

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

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

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

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

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

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

ОБНОВЛЕНИЕ: так как вы упомянули, что выше не работает, попробуйте перейти к среде выполнения:

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

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

Другие вопросы по тегам