Как перейти от уведомления Cocoa к вызову указателя функции c?

#objective-c #cocoa #smalltalk

#objective-c #cocoa #smalltalk

Вопрос:

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

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

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

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

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

Ответ №1:

Вам нужно будет создать класс glue в 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:amp;someCallbackFunction];
[[NSUserDefaultsController sharedUserDefaultsController]
    addObserver:self
    forKeyPath:[@"values." stringByAppendingString: @"MyPreference"]
    options:NSKeyValueObservingOptionNew
    context:NULL];
[glue release]; // only needed if not using ARC
 

Ответ №2:

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

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

Ответ №3:

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

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

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

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

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

Оглядываясь назад, нет необходимости MONFunctor быть классом; достаточно протокола.

Комментарии:

1. К сожалению, это мне не помогает, Джастин. Я не могу создавать новые классы ObjC. Просто используйте существующие, которые предоставляет среда выполнения objc.

2. @Travis ах! я не понимал, что это тоже ограничение.