2008-11-25 27 views
5

У меня есть метод в объективном классе C. Он имеет 2 функции обратного вызова, записанных на C. Указатель класса, то есть self, передается этим функциям как void *. В C-функциях я создаю указатель типа type и назначаю параметр 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); 
+0

Будет легче помочь, если вы можете редактировать, чтобы добавить код, который показывает, что вы пытаетесь сделать. – 2008-11-25 10:17:18

ответ

0

Это то, что селектор Objective-C является для: http://developer.apple.com/iphone/library/documentation/Cocoa/Reference/NSInvocationOperation_Class

API-интерфейс не очень интуитивным, но прекрасно, как только вы понимаете, что

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

1

Как правило, обратные вызовы в 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

Извините - до того, как был отправлен код, я подумал, что вопрос заключается в том, как писать код, который реализует систему обратного вызова в Objective-C, а не об использовании C-обратных вызовов. – 2008-11-25 22:33:41

10

Являются ли ваши проблемы специфичными для процедур обратного вызова IOKit? Проблема с конкретным примером, который вы указали, заключается в том, что IOServiceMatchingCallback принимает только 2 параметра, а не 3. Вам нужны ваши обратные вызовы RawDeviceAdded() и BulkTestDeviceAdded(), чтобы соответствовать прототипу IOServiceMatchingCallback и принять self в качестве первого параметра (refCon), а не 3-й. Кроме того, вам необходимо передать себя в качестве второго параметра последнего параметра 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 
Смежные вопросы