访问类别中的私有变量会导致链接器错误

时间:2010-12-13 13:25:54

标签: objective-c cocoa private linker-errors categories

编辑:我不会这样做,我现在意识到这有多危险。但是,问题仍然存在于纯粹的学术目的。

我正在尝试在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打印了它的内容。有谁知道解决这个问题的方法?

提前致谢!
比利

2 个答案:

答案 0 :(得分:12)

_displayedItems是私有的ivar,所以即使是从类别中也不应该访问它。

那就是说,你应该尝试使用

编译相同的代码
gcc -arch i386

gcc -arch x86_64

并看到差异。在32位模式下,您没有看到错误。这表明情况是多么脆弱。你真的不应该。

那就是说,有一种方法可以通过滥用KVC来获得这种伊娃:

@implementation NSCollectionView (displayedItems)

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

@end

请注意,您不应将方法命名为displayedItems。这会产生一个无限循环,因为KVC机器会比ivar更早地找到你的方法。见here

或者您可以使用Objective-C运行时函数访问任何隐藏的ivar。这也很有趣。

但是,让我再说一遍。知道你可以做一件事并做真实的事情有很大的不同。想想任何可怕的罪行。并亲自做到这一点。

不要那样!!!!!

答案 1 :(得分:5)

你不应该真的,但是像指向结构成员的指针一样访问它:

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

这是一件脆弱的事情,因为我确信你知道;)

更新:由于您已经提到上述功能无效,请尝试下载到运行时:

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

(经过测试,有效)