2008-11-25 5 views
5

J'ai une méthode dans une classe d'objectif-C. Il a 2 fonctions de rappel écrites en C. Le pointeur de classe, c'est-à-dire self, est passé à ces fonctions sous la forme void *. Dans les fonctions C, je crée un pointeur de type classe et affecte le paramètre void *. La première fonction de rappel s'exécute avec succès. Mais le pointeur void * devient nil dans la 2ème fonction de rappel. Notez que je n'ai pas modifié le pointeur dans le premier rappel mais je reçois toujours le nil dans le 2ème rappel.Traitement des rappels

Des idées sur ce qui pourrait mal tourner?

Par exemple:

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

RawDeviceAdded(NULL, gRawAddedIter, self); 

Cela fonctionne très bien. Mais la fonction ci-dessous reçoit self en tant que nil.

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

BulkTestDeviceAdded(NULL, gBulkTestAddedIter, self); 
+0

Il sera plus facile de vous aider si vous pouvez éditer pour ajouter du code qui montre ce que vous essayez de faire. –

Répondre

1

Généralement, les rappels dans Objective-C sont gérés en transmettant un objet délégué et un sélecteur à effectuer sur ce délégué. Par exemple, cette méthode appellera une méthode sur son délégué après la consignation d'un message, en passant lui-même et le message qui a été enregistré.

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

Vous pouvez l'appeler dans le code comme ceci:

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

Vous pouvez également utiliser objc_msgSend() directement à la place, si vous avez besoin de comprendre suffisamment le moteur d'exécution Objective-C pour choisir la variante à utiliser et comment pour construire le prototype et le pointeur de fonction à travers lequel l'appeler. (C'est le mécanisme par lequel les messages envoyés sont réellement implémentés dans Objective-C - ce à quoi le compilateur génère normalement des appels pour représenter les expressions [].)

+0

Désolé - avant la publication du code, je pensais que la question portait sur la façon d'écrire du code qui implémente un système de rappel dans Objective-C, pas sur l'utilisation des rappels C. –

10

Vos problèmes sont-ils spécifiquement liés aux routines de rappel IOKit? Le problème avec l'exemple spécifique que vous avez donné est que le IOServiceMatchingCallback prend seulement 2 paramètres, pas 3. Vous avez besoin de vos fonctions de rappel RawDeviceAdded() et BulkTestDeviceAdded() pour faire correspondre le prototype IOServiceMatchingCallback et accepter self comme premier paramètre (refCon), pas le 3ème. En outre, vous devez passer en self en tant que paramètre avant-dernier de IOServiceAddMatchingNotification() pour qu'il vous soit renvoyé par le rappel.

Une méthode courante pour gérer les rappels C dans le code Objective-C consiste simplement à avoir une fonction statique qui transfère le rappel à votre instance. Ainsi, votre exemple de code de rappel ressemblerait à ceci:

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