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

时间:2022-03-01 10:46:51

EDIT: I'm not going to do this, I now realize how dangerous this can be. But, the question stays for purely academic purposes.

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

I'm trying to implement a category on NSCollectionView that will let me access the private variable _displayedItems. I need to be able to access it in my subclass. So, I've created the following category:

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

@interface NSCollectionView (displayedItems)

- (NSMutableArray *)displayedItems;

@end


@implementation NSCollectionView (displayedItems)

- (NSMutableArray *)displayedItems
{
    return _displayedItems;
}

@end

...which seems like it should work perfectly. However, when I try to compile this, the linker gives me the following error:

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

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

I know for a fact that _displayedItems exists in NSCollectionView, I've looked at the interface and also printed it's contents using gdb. Does anyone know of a way to fix this?

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

Thanks in advance!
Billy

提前致谢!比利

2 个解决方案

#1


12  

_displayedItems is a private ivar, so you shouldn't access it, even from a category.

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

That said, you should try compiling the same code with

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

gcc -arch i386

and

gcc -arch x86_64

and see the difference. In the 32 bit mode you don't see the error. This shows how fragile the situation is. You really shouldn't.

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

That said, there's a way to get that ivar by abusing KVC:

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

@implementation NSCollectionView (displayedItems)

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

@end

Note that you shouldn't name your method just as displayedItems. That would make an infinite loop, because the KVC machinery would find your method earlier than the ivar. See here.

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

Or you can access any hidden ivar using Objective-C runtime functions. That's also fun.

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

However, let me say again. There's a big difference in knowing you can do one thing and doing that thing for real. Just think of any hideous crime. and doing that by yourself.

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

DON'T DO THAT!!!!!

#2


5  

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

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

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

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;
}

(Tested, works)

#1


12  

_displayedItems is a private ivar, so you shouldn't access it, even from a category.

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

That said, you should try compiling the same code with

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

gcc -arch i386

and

gcc -arch x86_64

and see the difference. In the 32 bit mode you don't see the error. This shows how fragile the situation is. You really shouldn't.

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

That said, there's a way to get that ivar by abusing KVC:

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

@implementation NSCollectionView (displayedItems)

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

@end

Note that you shouldn't name your method just as displayedItems. That would make an infinite loop, because the KVC machinery would find your method earlier than the ivar. See here.

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

Or you can access any hidden ivar using Objective-C runtime functions. That's also fun.

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

However, let me say again. There's a big difference in knowing you can do one thing and doing that thing for real. Just think of any hideous crime. and doing that by yourself.

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

DON'T DO THAT!!!!!

#2


5  

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

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

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

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;
}

(Tested, works)