如何在现代 OS X 版本上从 C 调用 objc_msgSend

How to call objc_msgSend from C on modern OS X versions

我需要从 C 对 OS X 上的 objc_msgSend 进行一些相对简单的调用。此代码用于工作 id event_data = objc_msgSend((id) objc_getClass("NSEvent"), sel_registerName("eventWithCGEvent:"), event_ref);,但是,Apple 最近将函数签名更改为 void objc_msgSend(void); 来解决一些问题。普遍的共识是,这应该用函数指针来解决,但是,如果没有关于 "function called through a non-compatible type" 和 "if this code is reached, the program will abort." 的一些不祥警告,我无法让它工作 我的新函数指针实现看起来像 id event_data = ((id (*)(id, SEL, CGEventRef)) objc_msgSend)((id) objc_getClass("NSEvent"), sel_registerName("eventWithCGEvent:"), event_ref); 但我担心这些警告。 event_ref 变量是定义为 CGEventRef event_ref 的函数参数。有没有人有想法使这项工作?

你可以试试:

id (*eventWithCGEvent)(Class, SEL, CGEventRef) = (id (*)(Class, SEL, CGEventRef)) objc_msgSend;

这定义了一个名为 eventWithCGEvent 的函数指针,它具有三个参数:一个接收器(因为它是一个 class 方法,所以它是 Class 类型)、选择器和一个CGEventRef.

类型的参数

在更多的上下文中,它可能看起来像这样:

#import "objc/message.h"
#import <CoreFoundation/CoreFoundation.h>
#import <CoreGraphics/CoreGraphics.h>


int main(int argc, const char * argv[]) {

    ...

    id (*eventWithCGEvent)(Class, SEL, CGEventRef) = (id (*)(Class, SEL, CGEventRef)) objc_msgSend;


    CGEventRef event_ref = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)42, true);

    Class NSEventClass = objc_getClass("NSEvent");
    SEL eventWithCGEventSelector = sel_registerName("eventWithCGEvent:");
    id event = eventWithCGEvent(NSEventClass, eventWithCGEventSelector, event_ref);
    CFRelease(event_ref);

    ...
    //do sth with event...
    ...

    return 0;
}