ивары при смешивании C и Objective-C - PullRequest
0 голосов
/ 24 октября 2010

Я пишу оболочку Objective-C для библиотеки C, и у меня возникают проблемы с доступом к ссылкам моих иваров.

Библиотека C требует, чтобы я указал указатель на функцию, которая обрабатывает события, я указал это во время инициализации моего класса Objective-C.

- (id) init {
    [super init];
    RegisterClient(&handleEvent);
    return self;
}

Библиотека C может начать поиск чего-либо и затем вызовет функцию handleEvent в случае, если что-то произошло во время поиска. Функция (в основном) выглядит следующим образом.

int handleEvent(void *Event) {
    [delegate didFinishSearching];
    return 0;
}

По крайней мере, я бы хотел, чтобы это выглядело так. Проблема в том, что код не будет создаваться из-за 'delegate' undeclared (first use in function) (конечно, я объявил его, я могу вызвать [delegate didFinishSearching] из любого метода Objective C, но не из функции C). Старые вопросы из stackoverflow предлагают определить дополнительную переменную (например, theDelegate) в заголовочном файле:

id theDelegate;

@interface Controller : NSObject {
    id delegate;
}
@property (assign) id delegate;
@end

Затем, всякий раз, когда я меняю значение delegate на новое, я должен присваивать это значение также theDelegate.

Так как мой C немного ржавый, вот мои вопросы:

1) Можно ли передать функции RegisterClient C указатель на метод Objective-C вместо указателя на функцию в качестве аргумента, чтобы полностью избежать функции C handleEvent?

2) Если нет: когда я создаю несколько экземпляров этого класса Objective-C, будет ли theDelegate одинаковым для всех экземпляров? (В конце концов, он не объявлен как переменная экземпляра ...)

Ответы [ 2 ]

3 голосов
/ 24 октября 2010

Методы Objective-C являются функциями C, но у них есть два скрытых параметра спереди, поэтому они не будут иметь подписи int f(void *).

Что вы, вероятно, хотите сделать, это использовать закрытие libffi. Это позволяет вам создать функцию с именно той сигнатурой, которая вам нужна, но она также имеет указатель на ваш объект, переданный вместе с ней. См. Пример на справочной странице ffi_prep_closure . Ваша handleEvent функция, вероятно, изменится и будет выглядеть примерно так:

static void handleEventClosure(ffi_cif * cif, void * result, void ** args, void * userdata)
{
    // Arguments.
    void * Event = *args[0];

    // Closed-over data.
    id delegate = (id)userdata;

    // Execute the method.
    [delegate didFinishSearching];

    // Smaller than sizeof(long), so use ffi_arg or ffi_sarg (unsigned or signed).
    *(ffi_sarg *)result = (ffi_sarg)0;
}
2 голосов
/ 25 октября 2010

В большинстве случаев библиотеки C, подобные описанным вами, принимают параметр userinfo, размер которого соответствует размеру указателя. Вы можете использовать это в своих интересах, передавая свой объект в качестве этого параметра "userinfo".

Затем в обратных вызовах вы возвращаете указатель на объект и делаете необходимые вызовы.

...