Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 在新运行时使用objc_msgSend而不使用强制转换的替代方法_Ios_Objective C_Objective C Runtime_Scripting Bridge - Fatal编程技术网

Ios 在新运行时使用objc_msgSend而不使用强制转换的替代方法

Ios 在新运行时使用objc_msgSend而不使用强制转换的替代方法,ios,objective-c,objective-c-runtime,scripting-bridge,Ios,Objective C,Objective C Runtime,Scripting Bridge,我正在编写一个objc桥,我发现了一种使用objc_msgSend调用objc方法的非常有效的方法 基本上,代码能够生成一个宏,该宏从NSArray传递给objc_msgSend正确数量的参数(需要metamacros.h) 一切都按预期进行,并且非常好,但不幸的是,我刚刚发现,由于Apple在最近的运行时中进行了更改,如果不显式转换到正确的函数指针,则无法直接调用objc_msgSend 发件人: : 尽管消息函数的原型具有可变形式,但Objective-C运行时调用的方法函数并不共享相同的原

我正在编写一个objc桥,我发现了一种使用objc_msgSend调用objc方法的非常有效的方法

基本上,代码能够生成一个宏,该宏从NSArray传递给objc_msgSend正确数量的参数(需要metamacros.h)

一切都按预期进行,并且非常好,但不幸的是,我刚刚发现,由于Apple在最近的运行时中进行了更改,如果不显式转换到正确的函数指针,则无法直接调用objc_msgSend

发件人: : 尽管消息函数的原型具有可变形式,但Objective-C运行时调用的方法函数并不共享相同的原型。Objective-C运行时直接分派给实现该方法的函数,因此调用约定不匹配,如前所述。因此,必须将objc_msgSend函数强制转换为与所调用的方法函数匹配的原型。”

例如:

- (int) doSomething:(int) x { ... }
- (void) doSomethingElse {
    int (*action)(id, SEL, int) = (int (*)(id, SEL, int)) objc_msgSend;
    action(self, @selector(doSomething:), 0);
}

显然,我无法为每个函数组合创建强制转换,因此我想知道什么是有效的替代方法。NSInvocation的速度太慢了。

有点困惑,因为对参数使用
NSArray肯定意味着它们都必须是对象类型

但是,除此之外,没有必要停止使用基于宏的方法,只需添加强制转换作为参数:

#define objc_call(RECIEVER, TYPE, SELECTOR, COUNT, ARR) \
(TYPE objc_msgSend)(RECIEVER, SELECTOR \
metamacro_for_cxt(COUNT, CFIEXTRACTARGS,, ARR) \
)
- (void) doSomethingElseThree
{
   NSArray *args = @[ @"three" ];
   NSString *res = objc_call2(self, @selector(doSomething:), 1, args);
   NSLog(@"res = %@", res);
}
并按如下方式使用:

- (NSString *) doSomething:(NSString *) x { ... }
(注意使用
NSString
——一种对象类型,不同于问题中的
int

附录

@RichardJ.Rossii在评论中表示,他认为您希望完全避免提供任何类型转换;而不是您希望避免为不同类型使用不同的宏,我认为是这样,并在上面提供了解决方案

鉴于您希望避免
NSInvocation
让我们再次查看您的宏。如前所述,它使用
NSArray
从中提取参数,因此每个参数都是一个对象,即
id
类型。如果所有参数都属于同一类型,则可能的强制转换数量将显著减少

我们考虑了参数,您希望支持多少种返回类型?假设现在是一个,<代码> ID >代码>。下面的两个宏最多可以执行19个参数:

#define metamacro_cast(COUNT) \
metamacro_at(COUNT, \
(id (*)(id, SEL)), \
(id (*)(id, SEL, id)), \
(id (*)(id, SEL, id, id)), \
(id (*)(id, SEL, id, id, id)), \
... // repeat until there are 19 id's
)

#define objc_call2(RECIEVER, SELECTOR, COUNT, ARR) \
(metamacro_cast(COUNT) objc_msgSend)(RECIEVER, SELECTOR \
metamacro_for_cxt(COUNT, CFIEXTRACTARGS,, ARR) \
)
此宏的用法与您的完全相同,没有额外的参数:

#define objc_call(RECIEVER, TYPE, SELECTOR, COUNT, ARR) \
(TYPE objc_msgSend)(RECIEVER, SELECTOR \
metamacro_for_cxt(COUNT, CFIEXTRACTARGS,, ARR) \
)
- (void) doSomethingElseThree
{
   NSArray *args = @[ @"three" ];
   NSString *res = objc_call2(self, @selector(doSomething:), 1, args);
   NSLog(@"res = %@", res);
}

如果你想支持多个返回类型,你要么需要多个
objc\u call\u returning\u type
宏;要么编写一个只接受返回类型的宏,不像我的第一个选择了整个演员阵容的宏,然后用
metamacros.h

尝试更多宏体操你可以和libffi混在一起,但是NSInvocation really是这样做的最佳选择。或者,你也可以手工制作一些汇编程序……不管怎样,这都是一个废话。我认为你没有抓住重点。问题不在于强制转换本身,而是确定要自动强制转换的函数指针类型。OP基本上不需要编写指针类型hims的代码elf@RichardJ.RossIII-你可能是对的,但是OP已经编写了一个宏,它扩展了一个
NSArray
,这个解决方案仍然这样做。它对OP有用吗?我不知道。@RichardJ.RossIII-你的建议让我想,添加了一个附录,可能会对OP有所帮助。我真的不知道哪一个最适合OP需要。