2

假设您想打开一个简单的警报框,在objective-c 世界中将类似于:

NSAlert *alert = [[[NSAlert alloc] init] autorelease];
    [alert setMessageText:@"Alert."];

    [alert beginSheetModalForWindow:window
                      modalDelegate:self
                     didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
                        contextInfo:nil];

beginModalForWindow 被定义为一个选择器方法。在苹果参考指南中,它的全名是“beginSheetModalForWindow:modalDelegate:didEndSelector:contextInfo:”

它在 NSAlert.h 中定义为:

- (void)beginSheetModalForWindow:(NSWindow *)window modalDelegate:(id)delegate didEndSelector:(SEL)didEndSelector contextInfo:(void *)contextInfo;

现在简单的问题,如何在 ruby​​ ffi 中定义这个方法?

module AppKit
  extend FFI::Library

  # Load the Cocoa framework's binary code
  ffi_lib '/System/Library/Frameworks/AppKit.framework/AppKit'

  attach_function :beginSheetModalForWindow, [:pointer,:pointer,:pointer], :bool
end

失败:

An exception occurred running ffi-test.rb
  Function 'beginSheetModalForWindow' not found in [/System/Library/Frameworks/AppKit.framework/AppKit] (FFI::NotFoundError)
4

1 回答 1

3

简而言之,你不能。至少不是没有大量的箍跳。

attach_function言行一致;它将一个C 函数绑定到 Ruby 运行时。 beginSheetModalForWindow:modalDelegate:didEndSelector:contextInfo:不是 C 函数;它是一个选择器。

您真正要绑定的是该选择器的实现

但不是真的。

您真正想要绑定的是objc_msgSend包含该方法的所有参数的类型签名。而且您还需要附加sel_getUid. 哦,你需要附上objc_lookUpClass

然后你会做类似(伪代码)的事情:

 ... attach objc_msgSend to msgSend with no arguments and object return type ...
 alert = msgSend(msgSend(msgSend(lookupClass("NSAlert"),getUid("alloc")),
           getUid("init")), getUid("autorelease"))

 ... attach objc_msgSend to bs with all the arguments for beginSheetModal....
 bs(alert, getUid("beginSheetModalForWindow:modalDelegate:didEndSelector:contextInfo", ... all the arguments ...))

或类似的东西。

此时,您已经重新发明了一种非常基本的MacRubyRubyCocoa形式。

于 2013-06-06T16:49:58.897 回答