2

我需要使用 NSInvocation 动态调用方法。这是我尝试过的:

NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[[messageRecord.senderController class] instanceMethodSignatureForSelector:messageRecord.receiverAction]];

[invocation setSelector:messageRecord.receiverAction];
[invocation setTarget: messageRecord.senderController];
[invocation setArgument: &(message.data) atIndex:2];
[invocation invoke];

需要提一下,messageRecord.senderController是调用哪个方法的对象,messageRecord.receiverAction是赋予这段代码的选择器。此外,message.data是一个类型为 (NSArray *) 的对象并已正确初始化。

这段代码给出了以下编译时错误

Address of property expression requested

当我如下更改调用过程时,它按预期工作:

NSArray *dataArray = message.data;

[invocation setSelector:messageRecord.receiverAction];
[invocation setTarget: messageRecord.senderController];
[invocation setArgument: &dataArray atIndex:2];
[invocation invoke];

两者之间的唯一区别是:我创建了一个本地 NSArray 指针并将 message.data 分配给它。后来,给出了新创建的指针的地址而不是message.data它本身。

为什么它起作用了?有什么区别呢?

4

2 回答 2

2

正如 Shimanski Ahem 提到的,财产不是有地址的东西。属性只是一对 getter 和 setter 方法。而已。getter 和 setter 方法可以由您提供,也可以由编译器根据某个实例变量合成。如果它们是你提供的,它们也可以基于一些实例变量,但是你需要做一些额外的逻辑;或者他们可以基于其他事物完全动态地生成价值。因此,与该属性相对应的某处可能没有一些“实例变量”。

如果 getter 和 setter 是合成的,并且您知道它们所基于的实例​​变量(您可以从 synthesize 声明中获得;如果 synthesize 没有明确指定,则它与属性名称相同;或者是_data(使用如果在最新版本的编译器中省略并隐式指定了综合,则在前面加下划线。这就是 Shimanski Artem 所显示的。

然而,退一步问一下,为什么你首先需要一个指向值的指针?什么目的?如果您使用指向原始值的指针或指向该值的副本的指针,会有所不同吗?了解该setArgument:方法的工作原理以及它为什么需要指针将帮助您回答其中的许多问题。setArgument:允许您使用您选择的值设置调用中的参数之一,因此它真正关心value。那么为什么不直接让你传递值呢?那么,它会是什么类型的呢?不同的类型在 C 中有不同的大小,所以这是不可能的。因此,它要求您提供一个指向该值的指针(适用于任何类型),然后从那里复制它。所以它只关心价值指向,而不是特定地址。这就是为什么(正如您所观察到的),当您想要使用setArgument:不可寻址的东西(如属性,或更复杂的表达式,或this在 Objective-C++ 中等)时,您可以简单地将其分配给一个临时变量,然后拿那个地址。

于 2012-11-28T21:57:31.970 回答
0

您不能获取财产的地址。这是语言细节。你可以试试这个表格:

[invocation setArgument: &(message->data) atIndex:2];
于 2012-11-28T10:02:35.777 回答