【问题标题】:Passing object pointer to performSelector:withObject results in EXC_BAD_ACCESS将对象指针传递给 performSelector:withObject 会导致 EXC_BAD_ACCESS
【发布时间】:2026-01-14 07:30:02
【问题描述】:

问题来了: 我通过[NSValue valueWithPointer:] 将一个指向对象的指针传递给performSelector:withObject,例如:

// GVertex is NSObject subclass
GVertex *vertex = [[GVertex alloc] initWithX:5.0f andY:4.5f]];
GVertex **vertexPtr = &vertex;
// later in code when I need to process the vertex
[self performSelector:@selector(processVertex:) withObject:[NSValue valueWithPointer:vertexPtr]];

然后在我的processVertex:(NSValue *)vertexValue 方法中,我想获取传递的顶点,我这样做:

- (void)parseVertex:(NSValue *)vertexValue
{
    GVertex *vertex = (GVertex *)[vertexValue pointerValue];
    ...
    [vertex setFlags:32]; <<-- This gives me EXC_BAD_ACCESS
    ... 
}

我在各处尝试了许多 (*) 和 (&) 的组合,但无法正常工作。 我究竟做错了什么 ?谢谢。

【问题讨论】:

  • 你在这段代码上运行过僵尸程序吗?如果您看到正在发送的消息,这可能会有所帮助。
  • 很难想象为什么需要将 一个对象 包装在一个 NSValue 中作为 pointerValue 以作为参数传递。这有点“代码味道”。
  • @bbum 是的,看起来是这样。我正在为自定义数据格式编写解析器,它需要在代码的几个不同区域中有多个 GVertex 对象实例。通过传递一个指针,processVertex 方法中的更改会反映在所有这些本地调用方法中。这样我的代码变得更加紧凑:)
  • 像这样通过引用传递会破坏封装并且非常脆弱。使顶点可变或将它们封装在其他东西中要好得多。

标签: objective-c pointers nsvalue


【解决方案1】:

你为什么不直接传递你的 vertex 对象:

[self performSelector:@selector(processVertex:) withObject:vertex];

并将您的方法声明更改为:

- (void)parseVertex:(GVertex *)vertex {
     [vertex setFlags:32];
}

【讨论】:

  • 这将是一个替代方案,但不是问题的解决方案。使用当前的实现,代码最终会变得更加复杂,并且至少是原来的 4 倍。此外,出于设计和灵活性的原因,我不想这样做。无论如何谢谢:)
【解决方案2】:

您放入NSValue 的指针是指向指针(或指针的地址)的指针,但您在检索它时就好像它是一个普通的对象指针。此外,您要获取其地址的指针是一个局部变量——该地址在新方法的上下文中将成为垃圾。

如果您只将(单个)指针存储在NSValue 中,这应该可以工作:

[self performSelector:@selector(processVertex:) withObject:[NSValue valueWithPointer:vertex]];

但请注意内存管理问题 -- NSValue 不会复制或获取该指针处的内存的所有权。

【讨论】:

  • 感谢您的回答,它解决了。但是,如果您同意,我还有另一个问题。如果我这样做,我会通过什么: [self performSelector:@selector(processVertex:) withObject:[NSValue valueWithPointer:&vertex]];我的意思是顶点变量之前的“&”?