这段代码为什么给EXC_BAD_ACCESS(使用IMP)

问题描述:

这段代码给了我EXC_BAD_ACCESS,为什么?这段代码为什么给EXC_BAD_ACCESS(使用IMP)

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++作为德默认语言/编译器,这个代码是在项目的开始

谢谢你们

+0

我无法重现。如果你把它放在一个新的项目中,你还会得到这个错误吗? – Chuck

+0

是的,我发现了...... ARC是问题所在。尝试在启用ARC的情况下创建新的iOS项目。然后复制并粘贴代码(我把它放在应用程序didFinishLaunchingWithOptions :) – subzero

您需要正确地投射函数指针,否则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,如果你找到函数指针语法不和谐。

+0

谢谢杰森。它起到了魅力的作用!问题:为什么会导致带有浮点参数的结构或方法的主要问题?如果您可以指向某个文档,我会更快乐。我刚刚发现“运行时”主题很有趣。 – subzero

+1

它与C中函数的调用约定以及参数如何传递有关。由于编译器不知道IMP中超过'self'和'_cmd'参数的任何参数,它只会将其他参数推送到堆栈上,并期望被调用函数知道如何处理它们。但是,如果被调用的函数需要一个浮点数,它几乎肯定会在GPR(对于ARM)或其他特定于fp的寄存器中,而不在堆栈中等。对于返回类型,结构与指针处理方式不同。 –

问题是IMP具有ARC将尝试管理的“id”的返回类型。您需要将您的函数指针投射到返回类型为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"); 
+0

'void(*)(id,SEL,...)'不是函数指针的正确类型。它是'void(*)(id,SEL,id,id)'。虽然它可能适用于某些类型('id')的某些体系结构的特定情况,但它通常不正确。 – newacct

+0

这实际上已经解决了。谢谢。 – Felipe