Обработка обратных вызовов - PullRequest
5 голосов
/ 25 ноября 2008

У меня есть метод в классе Objective-C. Он имеет 2 функции обратного вызова, написанные на C. Указатель класса, т.е. self, передается этим функциям как void *. В функциях C я создаю указатель типа class и назначаю параметр void *. Первая функция обратного вызова выполняется успешно. Но указатель void * становится nil во второй функции обратного вызова. Обратите внимание, что я не настроил указатель в первом обратном вызове, но все равно получаю nil во втором обратном вызове.

Есть идеи, что может пойти не так?

Например:

kr = IOServiceAddMatchingNotification(gNotifyPort, kIOFirstMatchNotification,
                                      matchingDict, RawDeviceAdded, NULL,
                                      &gRawAddedIter);

RawDeviceAdded(NULL, gRawAddedIter, self);

Это отлично работает. Но ниже функция получает self как nil.

kr = IOServiceAddMatchingNotification(gNotifyPort, kIOFirstMatchNotification,
                                      matchingDict, BulkTestDeviceAdded, NULL,
                                      &gBulkTestAddedIter);

BulkTestDeviceAdded(NULL, gBulkTestAddedIter, self);

Ответы [ 3 ]

11 голосов
/ 25 ноября 2008

Есть ли у вас проблемы именно с процедурами обратного вызова IOKit? Проблема с конкретным примером, который вы привели, состоит в том, что IOServiceMatchingCallback принимает только 2 параметра, а не 3. Вам нужны функции обратного вызова RawDeviceAdded () и BulkTestDeviceAdded (), чтобы соответствовать прототипу IOServiceMatchingCallback и принимать self в качестве первого параметра (refCon), а не 3-й. Кроме того, вам нужно передать self как второй к последнему параметру IOServiceAddMatchingNotification (), чтобы вернуть его вам обратным вызовом.

Обычный метод для обработки обратных вызовов C в коде Objective-C - просто иметь статическую функцию, которая перенаправляет обратный вызов вашему экземпляру. Итак, ваш пример кода обратного вызова будет выглядеть так:

static RawDeviceAdded(void* refcon, io_iterator_t iterator)
{
    [(MyClass*)refcon rawDeviceAdded:iterator];
}

@implementation MyClass
- (void)setupCallbacks
{
    // ... all preceding setup snipped
    kr = IOServiceAddMatchingNotification(gNotifyPort,kIOFirstMatchNotification, matchingDict,RawDeviceAdded,(void*)self,&gRawAddedIter );
    // call the callback method once to 'arm' the iterator
    [self rawDeviceAdded:gRawAddedIterator];
}
- (void)rawDeviceAdded:(io_iterator_t)iterator
{
    // take care of the iterator here, making sure to complete iteration to re-arm it
}
@end
1 голос
/ 25 ноября 2008

Как правило, обратные вызовы в Objective-C обрабатываются путем передачи объекта делегата и селектора для выполнения с этим делегатом. Например, этот метод вызовет метод для своего делегата после регистрации сообщения, передавая как себя, так и сообщение, которое было зарегистрировано.

- (void)logMessage:(NSString *)message
          delegate:(id)delegate
    didLogSelector:(SEL)didLogSelector
{
    NSLog(@"%@", message);

    if (delegate && didLogSelector && [delegate respondsToSelector:didLogSelector]) {
        (void) [delegate performSelector:didLogSelector
                              withObject:self
                              withObject:message];
    }
}

Вы можете назвать это в коде так:

- (void)sayHello
{
    [logger logMessage:@"Hello, world"
              delegate:self
        didLogSelector:@selector(messageLogger:didLogMessage:)];
}

- (void)messageLogger:(id)logger
        didLogMessage:(NSString *)message
{
    NSLog(@"Message logger %@ logged message '%@'", logger, message);
}

Вместо этого вы также можете использовать objc_msgSend() напрямую, хотя вам нужно достаточно понять среду выполнения Objective C, чтобы выбрать, какой вариант использовать и как создать прототип и указатель на функцию, через которую его вызывать. (Это механизм, с помощью которого отправка сообщений фактически реализуется в Objective-C - то, к чему компилятор обычно генерирует вызовы для представления [] выражений.)

0 голосов
/ 25 ноября 2008

Для этого предназначен селектор Objective-C: http://developer.apple.com/iphone/library/documentation/Cocoa/Reference/NSInvocationOperation_Class

API не очень интуитивно понятен, но хорошо, когда вы его понимаете

Возможно, вам также понадобится провести некоторый рефакторинг, но теперь может быть лучший способ, но когда у меня возникла эта проблема, я решил реорганизовать и использовать InvoationOperation.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...