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

vil*_*mer 10 cocoa private objective-c linker-errors categories

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

我正在尝试在NSCollectionView上实现一个类别,它允许我访问私有变量_displayedItems.我需要能够在我的子类中访问它.所以,我创建了以下类别:

@interface NSCollectionView (displayedItems)

- (NSMutableArray *)displayedItems;

@end


@implementation NSCollectionView (displayedItems)

- (NSMutableArray *)displayedItems
{
    return _displayedItems;
}

@end
Run Code Online (Sandbox Code Playgroud)

......看起来它应该完美无缺.但是,当我尝试编译它时,链接器给我以下错误:

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
Run Code Online (Sandbox Code Playgroud)

我知道_displayedItems存在于NSCollectionView中,我查看了界面并使用gdb打印了它的内容.有谁知道解决这个问题的方法?

提前致谢!
比利

Yuj*_*uji 12

_displayedItems 是一个私人的ivar,所以你不应该访问它,即使是从一个类别.

也就是说,您应该尝试使用相同的代码编译

gcc -arch i386
Run Code Online (Sandbox Code Playgroud)

gcc -arch x86_64
Run Code Online (Sandbox Code Playgroud)

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

也就是说,有一种方法可以通过滥用KVC来获得这种静脉注射:

@implementation NSCollectionView (displayedItems)

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

@end
Run Code Online (Sandbox Code Playgroud)

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

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

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

不要那样!!!!!


d11*_*wtq 5

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

-(NSMutableArray *)displayedItems {
  return self->_displayedItems;
}
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

(Tested, works)

  • 这是技术上正确的答案,但不是道德上正确的答案:p (3认同)