2008-11-25 20 views
5

Tengo un método en una clase de objetivo-C. Tiene 2 funciones de devolución de llamada escritas en C. El puntero de clase, es decir, self se pasa a estas funciones como void *. En las funciones C, creo un puntero de tipo clase y asigno el parámetro void *. La primera función de devolución de llamada se ejecuta con éxito. Pero el puntero void * se convierte en nil en la segunda función de devolución de llamada. Tenga en cuenta que no he modificado el puntero en la primera devolución de llamada, pero igual recibo nil en la segunda devolución de llamada.Manejo de devoluciones de llamada

¿Alguna idea de lo que podría estar yendo mal?

Por ejemplo:

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

RawDeviceAdded(NULL, gRawAddedIter, self); 

Esto funciona bien. Pero debajo de la función recibe self como nil.

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

BulkTestDeviceAdded(NULL, gBulkTestAddedIter, self); 
+0

Será más fácil ayudar si puede editar para agregar código que muestra lo que está tratando de hacer. –

Respuesta

1

Generalmente, las devoluciones de llamada en Objective-C se manejan pasando un objeto de delegado y un selector para realizar en ese delegado. Por ejemplo, este método llamará a un método en su delegado después de registrar un mensaje, pasando él mismo y el mensaje que se registró.

- (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]; 
    } 
} 

Se le puede llamar en código como este:

- (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); 
} 

También puede utilizar objc_msgSend() directamente en lugar, sin embargo es necesario entender el tiempo de ejecución de Objective-C suficiente para elegir la variante que debe usar y la para construir el prototipo y el puntero de función a través del cual llamarlo. (Es el mecanismo por el cual los mensajes enviados realmente se implementan en Objective-C - a lo que el compilador normalmente genera llamadas para representar expresiones [].)

+0

Lo siento: antes de que se publicara el código, pensé que la pregunta era sobre cómo escribir código que implementa un sistema de devolución de llamada en Objective-C, no sobre usar callbacks de C. –

10

¿Están sus problemas específicamente con las rutinas de devolución de llamada de IOKit? El problema con el ejemplo específico que dio es que IOServiceMatchingCallback toma solo 2 parámetros, no 3. Necesita las funciones de devolución de llamada RawDeviceAdded() y BulkTestDeviceAdded() para que coincidan con el prototipo IOServiceMatchingCallback y aceptarse como el primer parámetro (refCon), no la tercera. Además, debe pasar self como el segundo y último parámetro de IOServiceAddMatchingNotification() para que la devolución de llamada lo devuelva.

Un método común para manejar devoluciones de llamada C en código Objective-C es simplemente tener una función estática que reenvía la devolución de llamada a su instancia. Por lo tanto, su código de devolución de llamada de ejemplo se vería así:

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 
Cuestiones relacionadas