如何从Cocoa Notification蹦床到调用c函数指针?

时间:2011-10-27 04:22:40

标签: objective-c cocoa smalltalk

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

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

我是在Smalltalk环境中这样做的。特定的Smalltalk实际上可以通过objective-c运行时功能来驱动上述内容。问题是“自我”作为addObserver:参数。从Smalltalk,我可以创建一个C函数指针,它将作为Smalltalk的回调函数。但它无法提供Object对ObjectiveC环境的概念。

所以我试图弄清楚如何使用适当的API从某种对象中蹦出来导致我创建的函数指针被执行。我查看了NSInvokation和朋友,但没有一个用于包裹C函数指针。而且我不确定他们是否会翻译addObserver:forKeyPath:options:context:来做正确的事。

归结为问题是,如何使用现有的Cocoa对象来注册对Notification的响应,该响应是执行C函数指针而不编译任何新的objc代码。

3 个答案:

答案 0 :(得分:2)

您需要在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

答案 1 :(得分:1)

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

希望这适合你:)

答案 2 :(得分:0)

使用简单的函数对象:

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

然后根据需要专门化:

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

你可以使用仿函数作为监听器,但我勾勒出这个,好像你的监听器只会在回调中说[functor performFunction];

回想起来,MONFunctor不需要成为一个班级;一个协议就足够了。