Ios 在新运行时使用objc_msgSend而不使用强制转换的替代方法
我正在编写一个objc桥,我发现了一种使用objc_msgSend调用objc方法的非常有效的方法 基本上,代码能够生成一个宏,该宏从NSArray传递给objc_msgSend正确数量的参数(需要metamacros.h) 一切都按预期进行,并且非常好,但不幸的是,我刚刚发现,由于Apple在最近的运行时中进行了更改,如果不显式转换到正确的函数指针,则无法直接调用objc_msgSend 发件人: : 尽管消息函数的原型具有可变形式,但Objective-C运行时调用的方法函数并不共享相同的原型。Objective-C运行时直接分派给实现该方法的函数,因此调用约定不匹配,如前所述。因此,必须将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运行时调用的方法函数并不共享相同的原
- (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需要。