如何从 Cocoa 通知跳转到 c 函数指针的调用?

发布于 2024-12-12 01:38:32 字数 677 浏览 0 评论 0原文

我想在我的环境中设置类似的东西。

[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self
    forKeyPath:[@"values." stringByAppendingString: @"MyPreference"]
    options:NSKeyValueObservingOptionNew
    context:NULL];

我是在 Smalltalk 环境中执行此操作的。特定的 Smalltalk 实际上可以通过 Objective-C 运行时功能来驱动上述内容。问题在于 addObserver: 参数中的“self”。在 Smalltalk 中,我可以创建一个 C 函数指针,它将充当 Smalltalk 的回调。但它无法向 ObjectiveC 环境提供对象的概念。

因此,我试图弄清楚如何使用适当的 API 从某种对象中进行蹦床,从而导致我创建的函数指针被执行。我看过 NSInvokation 和朋友,但这些都不是用来包装 C 函数指针的。我不确定他们会翻译 addObserver:forKeyPath:options:context: 来做正确的事情。

归根结底,问题是,如何使用现有的 Cocoa 对象来注册对通知的响应,即执行 C 函数指针,而无需编译任何新的 objc 代码。

I want to set up something like this in my environment.

[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self
    forKeyPath:[@"values." stringByAppendingString: @"MyPreference"]
    options:NSKeyValueObservingOptionNew
    context:NULL];

I'm doing this from a Smalltalk environment. The particular Smalltalk can actually drive the above thru the objective-c runtime features. The problem is the "self" there as the addObserver: argument. From Smalltalk, I can create an C function pointer that will act as a callback into Smalltalk. But it can't offer it's notion of what an Object is to the ObjectiveC environment.

So I'm trying to figure out how to trampoline from some sort of object with the appropriate API that causes the function pointer I create to be executed. I've looked at NSInvokation and friends, but none of those are used to wrap around a C function pointer. And I'm not sure they'd translate the addObserver:forKeyPath:options:context: to do the right thing.

Boiled down the question is, how do you use existing Cocoa objects to register a response to a Notification that is the execution of a C function pointer without compiling any new objc code.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦断已成空 2024-12-19 01:38:32

您需要在 Objective-C 中创建一个粘合类。您可以这样做:

typedef void TravisGriggsCallback();

@interface TravisGriggsGlue {
    TravisGriggsCallback *_callback;
}
- (id)initWithCallback:(TravisGriggsCallback *)callback;
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
    change:(NSDictionary *)change context:(void *)context
@end

@implementation TravisGriggsGlue

 - (id)initWithCallback:(TravisGriggsCallback *)callback
{
    if (!(self = [super init]))
        return nil;
    _callback = callback;
    return self;
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
    change:(NSDictionary *)change context:(void *)context
{
    _callback();
}

@end

如果需要将参数传递给回调,则需要添加实例变量来保存参数,并将它们传递给 init 方法。

然后你像这样使用它:

TravisGriggsGlue *glue = [[TravisGriggsGlue alloc]
    initWithCallback:&someCallbackFunction];
[[NSUserDefaultsController sharedUserDefaultsController]
    addObserver:self
    forKeyPath:[@"values." stringByAppendingString: @"MyPreference"]
    options:NSKeyValueObservingOptionNew
    context:NULL];
[glue release]; // only needed if not using ARC

You'll need to create a glue class in Objective-C. You could do this:

typedef void TravisGriggsCallback();

@interface TravisGriggsGlue {
    TravisGriggsCallback *_callback;
}
- (id)initWithCallback:(TravisGriggsCallback *)callback;
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
    change:(NSDictionary *)change context:(void *)context
@end

@implementation TravisGriggsGlue

 - (id)initWithCallback:(TravisGriggsCallback *)callback
{
    if (!(self = [super init]))
        return nil;
    _callback = callback;
    return self;
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
    change:(NSDictionary *)change context:(void *)context
{
    _callback();
}

@end

If you need to pass arguments to the callback, you'll need to add instance variables to hold the arguments, and pass them to the init method.

Then you use it like this:

TravisGriggsGlue *glue = [[TravisGriggsGlue alloc]
    initWithCallback:&someCallbackFunction];
[[NSUserDefaultsController sharedUserDefaultsController]
    addObserver:self
    forKeyPath:[@"values." stringByAppendingString: @"MyPreference"]
    options:NSKeyValueObservingOptionNew
    context:NULL];
[glue release]; // only needed if not using ARC
暖伴 2024-12-19 01:38:32

我不知道你使用的是哪种 Smalltalk,但在 pharo/squeak 中你可能使用的是 ObjectiveCBridge 插件。如果是这种情况,您可以扩展 ObjectiveCSqueakProxy 并将其用作从 cocoa 委托给您的应用程序的对象。

希望这对你有用:)

I don't know which kind of Smalltalk you're using, but in pharo/squeak you are probably using the ObjectiveCBridge plugin. If that is the case, you can extend an ObjectiveCSqueakProxy and use it as an object delegated from cocoa to your application.

hope this works for you :)

爱给你人给你 2024-12-19 01:38:32

使用一个简单的函数对象:

@interface MONFunctor : NSObject
- (void)performFunction;
@end

然后根据需要进行专门化:

@interface MONFunctorSpecialization : NSObject
{
@private
// data, state, arguments for function, function pointer...
}
- (void)performFunction;
@end

您可以使用函子作为侦听器,但我将其概述为好像您的侦听器只会在回调中说 [functor PerformFunction];

回想起来,MONFunctor 没有必要成为一个类;一个协议就足够了。

use a simple function object:

@interface MONFunctor : NSObject
- (void)performFunction;
@end

Then just specialize as needed:

@interface MONFunctorSpecialization : NSObject
{
@private
// data, state, arguments for function, function pointer...
}
- (void)performFunction;
@end

You could use the functor as a listener, but I sketched this out as though your listener would just say [functor performFunction]; in the callback.

In retrospect, there's no need for MONFunctor to be a class; a protocol would suffice.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文