Gestion correcte de addObserverForName: object: queue: usingBlock:

Je suis encore nouveau sur les blocs dans l'objective-c et je me request si j'ai ce code correct. Je ne suis pas sûr s'il suffit de supprimer l'observateur ou si je dois appeler removeObserver: name: object:

-(void) scan { Scanner *scanner = [[Scanner alloc] init]; id scanComplete = [[NSNotificationCenter defaultCenter] addObserverForName:@"ScanComplete" object:scanner queue:nil usingBlock:^(NSNotification *notification){ /* do something */ [[NSNotificationCenter defaultCenter] removeObserver:scanComplete]; [scanner release]; }]; [scanner startScan]; } 

Mise à jour: Je reçois EXC_BAD_ACCESS intermittent de ce bloc, donc cela ne peut pas être correct.

Déclarez la variable scanComplete avant de définir le bloc lui-même.

La raison pour laquelle vous devez faire cela est parce que vous essayez d'accéder à une variable qui n'existe pas dans le bloc au moment de la définition puisque la variable elle-même n'a pas encore été assignée.

Qu'est-ce que EXC_BAD_ACCESS ? Eh bien, c'est une exception qui est levée lorsque vous essayez d'accéder à une reference qui n'existe pas. C'est exactement le cas dans votre exemple.

Donc, si vous déclarez la variable avant le bloc lui-même, alors cela devrait fonctionner:

 -(void) scan { Scanner *scanner = [[Scanner alloc] init]; __block id scanComplete; scanComplete = [[NSNotificationCenter defaultCenter] addObserverForName:@"ScanComplete" object:scanner queue:nil usingBlock:^(NSNotification *notification){ /* do something */ [[NSNotificationCenter defaultCenter] removeObserver:scanComplete]; [scanner release]; }]; [scanner startScan]; } 

Vous ne devriez pas vous désinscrire dans le bloc de registre. Au lieu de cela, stockez le jeton renvoyé par addObserverForName (dans ce cas, votre scanComplete ) en tant que variable d'instance ou dans une collection qui est une variable d'instance et désinscrivez-vous plus tard lorsque vous êtes sur le sharepoint disparaître. Ce que je fais est de garder un NSMutableSet appelé observers . Alors:

 id ob = [[NSNotificationCenter defaultCenter] addObserverForName:@"whatever" object:nil queue:nil usingBlock:^(NSNotification *note) { // ... whatever ... }]; [self->observers addObject:ob]; 

Et plus tard:

 for (id ob in self->observers) [[NSNotificationCenter defaultCenter] removeObserver:ob]; self->observers = nil; 

Apple Document sur cette méthode:

L'exemple suivant montre comment vous pouvez vous inscrire pour recevoir des notifications de modification des parameters régionaux.

 NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; NSOperationQueue *mainQueue = [NSOperationQueue mainQueue]; self.localeChangeObserver = [center addObserverForName:NSCurrentLocaleDidChangeNotification object:nil queue:mainQueue usingBlock:^(NSNotification *note) { NSLog(@"The user's locale changed to: %@", [[NSLocale currentLocale] localeIdentifier]); }]; 

Pour annuler l'logging des observations, vous passez l'object renvoyé par cette méthode à removeObserver :. Vous devez appeler removeObserver: ou removeObserver: name: object: avant tout object spécifié par addObserverForName: object: queue: usingBlock: est désalloué.

 NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; [center removeObserver:self.localeChangeObserver]; 

La scope du bloc n'a pas l'autorisation de libérer l'object scanner. Si vous n'utilisez pas le garbage collection, la suppression de la release et la release automatique du scanner ( [[[Scanner alloc] init] autorelease] ) devraient faire l'affaire.

Vous devriez également pouvoir déplacer l'appel vers removeObserver en toute removeObserver dehors du bloc.

Dans le cas de EXC_BAD_ACCESS : Entrer bt dans la window de la console après le plantage de l'application vous donnera un backtrace, et devrait vous informer où l'erreur s'est produite.