#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 ах! я не понимал, что это тоже ограничение.