【问题标题】:why does this code give EXC_BAD_ACCESS (using IMP)为什么这段代码会给出 EXC_BAD_ACCESS(使用 IMP)
【发布时间】:2012-06-08 16:56:05
【问题描述】:

这段代码给了我 EXC_BAD_ACCESS,为什么?

NSMutableDictionary  *d = [[NSMutableDictionary alloc] init];
IMP imp= [d methodForSelector:@selector(setObject:forKey:) ];
imp(d,  @selector( setObject:forKey:), @"obj", @"key");

我刚开始使用 IMP,先试试吧.. 不走运。不知道为什么我会收到错误,也.. 过去,当我收到 EXC_BAD_ACCESS 时,在控制台打印了消息,这次错误行突出显示。

一些注意事项: ARC已启用,XCode 4.3.2,项目使用Objective-C++作为de默认语言/编译器,此代码在项目的最开始

谢谢大家

【问题讨论】:

  • 我无法复制。如果你把它放在一个新的项目中,你还会得到错误吗?
  • 是的,我发现... ARC 是问题所在。尝试创建一个启用 ARC 的新 iOS 项目。然后将代码复制并粘贴到某处(我将其放在应用程序 didFinishLaunchingWithOptions 中:)

标签: objective-c objective-c++ objective-c-runtime


【解决方案1】:

您需要正确地转换函数指针,否则 ARC 不知道它应该做什么。 IMP 是一个通用函数指针,它接受一个 id、一个选择器和可变数量的其他未定义参数并返回一个 id。您尝试调用的方法实现需要一个 id,一个选择器后跟两个 id 参数,并且返回类型为 void。您可以通过更改为以下代码来修复它:

NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];
void (*imp)(id, SEL, id, id) = (void(*)(id,SEL,id,id))[dict methodForSelector:@selector(setObject:forKey:)];
if( imp ) imp(dict, @selector(setObject:forKey:), @"obj", @"key");

在取消引用之前,您应该始终检查您是否确实获得了函数指针,因为这也会崩溃。上面的代码甚至可以在 ARC 环境中工作。此外,即使您不使用 ARC,您也应该始终将函数指针转换为实际原型而不是 IMP。你永远不应该使用 IMP。其他会导致主要问题的地方是该方法是否返回结构或该方法是否采用浮点参数等。

好习惯:如果你发现函数指针语法不和谐,请始终转换你的函数指针或为它们制作 typedef。

【讨论】:

  • 谢谢杰森。它起到了魅力!问题:为什么它会导致带有浮点参数的结构或方法出现重大问题?如果你能指出一些文档,我会更高兴。我刚刚发现“运行时”主题很有趣。
  • 这与C中函数的调用约定以及参数的传递方式有关。由于编译器对 IMP 的 self_cmd 参数一无所知,它只会将其他参数压入堆栈并期望被调用的函数知道如何处理它们。但是,如果被调用函数需要一个浮点数,它几乎肯定会在 GPR(对于 ARM)或其他特定于 fp 的寄存器中查找,而不是在堆栈上等。返回类型也是如此,结构的处理方式与指针不同。
【解决方案2】:

问题在于 IMP 的返回类型为“id”,ARC 将尝试对其进行管理。您需要将函数指针转换为具有 void 的返回类型(与您正在调用的方法一致):

    NSMutableDictionary  *d = [[NSMutableDictionary alloc] init];
    IMP imp= [d methodForSelector: @selector(setObject:forKey:)];
    void (*func)(__strong id,SEL,...) = (void (*)(__strong id, SEL, ...))imp;
    func( d,  @selector(setObject:forKey:), @"obj", @"key" );

【讨论】:

  • void (*)(id, SEL, ...) 不是函数指针的正确类型。它是void (*)(id, SEL, id, id)。尽管它可能适用于具有某些类型的某些体系结构 (id),但总体而言它是不正确的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多