Как добраться из уведомления Какао до вызова указателя на функцию c? - PullRequest
5 голосов
/ 27 октября 2011

Я хочу настроить что-то подобное в моей среде.

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

Я делаю это из среды Smalltalk. Конкретный Smalltalk может фактически управлять вышеупомянутыми функциями во время выполнения target-c. Проблема в том, что «я» есть аргумент addObserver:. Из Smalltalk я могу создать указатель на функцию C, который будет выполнять функцию обратного вызова в Smalltalk. Но он не может предложить понятие о том, что представляет собой Объект для среды ObjectiveC.

Итак, я пытаюсь понять, как батутить из какого-то объекта с помощью соответствующего API, который вызывает выполнение указателя функции, который я создаю. Я посмотрел на NSInvokation и друзей, но ни один из них не используется, чтобы обернуть указатель на функцию C. И я не уверен, что они переведут addObserver:forKeyPath:options:context:, чтобы поступить правильно.

Суть вопроса в том, как использовать существующие объекты Какао для регистрации ответа на Уведомление, являющееся выполнением указателя на функцию C, без компиляции какого-либо нового кода objc.

Ответы [ 3 ]

2 голосов
/ 27 октября 2011

Вам нужно будет создать класс склеивания в 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 голос
/ 27 октября 2011

Я не знаю, какой тип Smalltalk вы используете, но в pharo / squeak вы, вероятно, используете плагин ObjectiveCBridge. Если это так, вы можете расширить ObjectiveCSqueakProxy и использовать его в качестве объекта, делегированного из какао вашему приложению.

надеюсь, что это работает для вас:)

0 голосов
/ 27 октября 2011

используйте простой объект функции:

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

Тогда просто специализируйтесь по мере необходимости:

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

Вы можете использовать функтор в качестве слушателя, но я набросал это так, как будто ваш слушатель просто скажет [functor performFunction]; в обратном вызове.

В ретроспективе нет необходимости для MONFunctor быть классом; протокол будет достаточно.

...