Question

J'ai un NSOperation. Une fois terminé, je tire un NSNotificationCenter pour laisser le programme savoir que le NSOperation est terminé et mettre à jour l'interface utilisateur graphique.

Pour mes auditeurs à la compréhension NSNotification ne fonctionnera pas sur le thread principal car le NSOperation n'est pas sur le thread principal.

Comment puis-je faire en sorte que les auditeurs courent sur le thread principal quand je tire mon événement?

[[NSNotificationCenter defaultCenter] postNotificationName:@"myEventName" object:self]; 
Était-ce utile?

La solution

Vous pouvez utiliser performSelectorOnMainThread:withObject:waitUntilDone: à l'aide d'une méthode d'assistance, d'une manière similaire à l'exemple suivant

.....
[self performSelectorOnMainThread:@selector(fireNotification) withObject:nil waitUntilDone:YES];
...

- (void)fireNotification {
  [[NSNotificationCenter defaultCenter] postNotificationName:@"myEventName" object:self]; 
}

Si vous n'attendez pas avant d'être fait, vous devrez tenir compte des cas où d'autres threads peuvent se référer à l'objet qui pourrait être déjà nettoyé avant que le thread principal s'invoqué.

Autres conseils

Mise à jour: les files d'attente font Dispatch affichant une notification sur le thread principal très facile.

dispatch_async(dispatch_get_main_queue(),^{
   [[NSNotificationCenter defaultCenter] postNotification...];
});

Pour attendre les gestionnaires de notification pour terminer, il suffit de remplacer dispatch_async avec dispatch_sync.


Après la réponse de notnoop, voici quelques infrastructures que vous pouvez utiliser pour poster en toute sécurité vos notifications sur le thread principal sans en attendant qu'ils aient fini. Espérons que quelqu'un trouve cela utile!

NSNotificationCenter + Utils.h:

@interface NSNotificationCenter (Utils)

-(void)postNotificationOnMainThread:(NSNotification *)notification;
-(void)postNotificationNameOnMainThread:(NSString *)aName object:(id)anObject;
-(void)postNotificationNameOnMainThread:(NSString *)aName object:(id)anObject userInfo:(NSDictionary *)aUserInfo;

@end

NSNotificationCenter + Utils.m:

@interface NSNotificationCenter (Utils_Impl) {
}

-(void)postNotificationOnMainThreadImpl:(NSNotification*)notification;
-(void)postNotificationNameOnMainThreadImpl:(NSString *)aName object:(id)anObject userInfo:(NSDictionary *)aUserInfo;

@end

@implementation NSNotificationCenter (Utils)

-(void)postNotificationOnMainThread:(NSNotification *)notification {
    [notification retain];
    [notification.object retain];
    [self performSelectorOnMainThread:@selector(postNotificationOnMainThreadImpl:) 
                           withObject:notification
                        waitUntilDone:NO];
}

-(void)postNotificationNameOnMainThread:(NSString *)aName object:(id)anObject {
    [self postNotificationNameOnMainThread:aName object:anObject userInfo:nil];
}

-(void)postNotificationNameOnMainThread:(NSString *)aName object:(id)anObject userInfo:(NSDictionary *)aUserInfo {
    [aName retain];
    [anObject retain];
    [aUserInfo retain];

    SEL sel = @selector(postNotificationNameOnMainThreadImpl:object:userInfo:);
    NSMethodSignature* sig = [self methodSignatureForSelector:sel];
    NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:sig];
    [invocation setTarget:self];
    [invocation setSelector:sel];
    [invocation setArgument:&aName atIndex:2];
    [invocation setArgument:&anObject atIndex:3];
    [invocation setArgument:&aUserInfo atIndex:4];
    [invocation invokeOnMainThreadWaitUntilDone:NO];
}

@end

@implementation NSNotificationCenter (Utils_Impl)

-(void)postNotificationOnMainThreadImpl:(NSNotification*)notification {
    [self postNotification:notification];
    [notification.object release];
    [notification release];
}

-(void)postNotificationNameOnMainThreadImpl:(NSString *)aName object:(id)anObject userInfo:(NSDictionary *)aUserInfo {
    [self postNotificationName:aName object:anObject userInfo:aUserInfo];
    [aName release];
    [anObject release];
    [aUserInfo release];
}

@end

NSInvocation + Utils.h:

@interface NSInvocation (Utils)

-(void)invokeOnMainThreadWaitUntilDone:(BOOL)wait;

@end

NSInvocation + Utils.m:

@implementation NSInvocation (Utils)

-(void)invokeOnMainThreadWaitUntilDone:(BOOL)wait
{
    [self performSelectorOnMainThread:@selector(invoke)
                           withObject:nil
                        waitUntilDone:wait];
}

@end

Si vous êtes sur 10.6, vous pouvez également utiliser setCompletionBlock: . Il est utilisé comme ceci:

NSOperation*op= .... ;
[op setCompletionBlock:^{
    dispatch_async(dispatch_get_main_queue(),^{
        code to be run on the main thread after the operation is finished.
    });
}];

Pour l'introduction générale sur les blocs et GCD, cet article a été extrêmement utile. J'ai trouvé GCD et setCompletionBlock plus facile à lire que NSNotification. Une mise en garde est, bien, il ne fonctionne que sur 10.6!

Pour développer la réponse de Danra est ici l'ARC version conforme de la catégorie I mis en place:

NSNotificationCenter + Threads.h

@interface NSNotificationCenter (Threads)

-(void)postNotificationOnMainThread:(NSNotification *)notification;
-(void)postNotificationNameOnMainThread:(NSString *)name object:(id)object;
-(void)postNotificationNameOnMainThread:(NSString *)name object:(id)object userInfo:(NSDictionary *)userInfo;

@end

NSNotificationCenter + Threads.m

@implementation NSNotificationCenter (Threads)

-(void)postNotificationOnMainThread:(NSNotification *)notification
{
    [self performSelectorOnMainThread:@selector(postNotification:) withObject:notification waitUntilDone:NO];
}

-(void)postNotificationNameOnMainThread:(NSString *)name object:(id)object
{
    [self postNotificationNameOnMainThread:name object:object userInfo:nil];
}

-(void)postNotificationNameOnMainThread:(NSString *)name object:(id)object userInfo:(NSDictionary *)userInfo
{
    dispatch_async(dispatch_get_main_queue(), ^{
        [self postNotificationName:name object:object userInfo:userInfo];
    });
}

@end
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top