【问题标题】:Accessing private variable in Category results in linker error访问 Category 中的私有变量会导致链接器错误
【发布时间】:2011-05-24 16:11:00
【问题描述】:

编辑:我不打算这样做,我现在意识到这有多危险。但是,这个问题仅用于学术目的。

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

提前致谢!
比利

【问题讨论】:

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


【解决方案1】:

_displayedItems 是私有 ivar,因此您不应访问它,即使是从类别中也是如此。

也就是说,你应该尝试用

编译相同的代码
gcc -arch i386

gcc -arch x86_64

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

也就是说,有一种方法可以通过滥用 KVC 来获取该 ivar:

@implementation NSCollectionView (displayedItems)

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

@end

请注意,您不应将方法命名为 displayedItems。这会造成无限循环,因为 KVC 机制会比 ivar 更早地找到您的方法。见here

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

但是,让我再说一遍。知道你可以做一件事和真正做那件事有很大的不同。想想任何可怕的罪行。并自己做。

不要那样做!!!!!!

【讨论】:

  • 我会将“不要那样做”移到顶部。 :) 如果你开始搞乱框架类的内部状态,随着时间的推移,你肯定会对崩溃和神秘的失败感到惊讶。
  • @bbum 不是另一个答案中建议的object_getInstanceVariable 相对无害吗?
  • 您正在将状态挂在其内部实现细节可能发生变化的对象上。考虑 NSNumber,它的值可能是单例并且每个平台都会发生变化。将统计信息注入中间系统类是糟糕的设计。 @yar
  • 感谢@bbum,真的,它破坏了封装,感谢您的回复。
【解决方案2】:

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

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

这是一件很脆弱的事情,但我相信你也知道 ;)

更新:由于您提到上述方法不起作用,请尝试下拉到运行时:

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

(经过测试,有效)

【讨论】:

  • 这也不起作用,它给出了相同的错误。不过感谢您的建议!
  • 这是一个技术上正确的答案,但不是一个道德上正确的答案:p
  • 是的,我认为 OP 已经决定根据问题的性质忽略对脆弱性的任何担忧,但我 100% 同意你的观点 :)
  • 这确实有效,但我决定听取不这样做的请求,并设计了另一种获取信息的方法,不需要任何不道德的东西。 :) 还是谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-15
  • 2023-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-09
相关资源
最近更新 更多