2009-12-29 27 views
18

Tengo una NSOperation. Cuando termina, disparo un NSNotificationCenter para informar al programa que la NSoperation ha finalizado y para actualizar la interfaz gráfica de usuario.NSOperation y NSNotificationCenter en el hilo principal

Para mi comprensión, los oyentes de NSNotification no se ejecutarán en el hilo principal porque NSOperation no está en el hilo principal.

¿Cómo puedo hacerlo para que los oyentes se ejecuten en el hilo principal cuando dispare mi evento?

[[NSNotificationCenter defaultCenter] postNotificationName:@"myEventName" object:self]; 

Respuesta

22

Puede utilizar performSelectorOnMainThread:withObject:waitUntilDone: con el uso de un método de ayuda, de una manera similar al ejemplo siguiente.

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

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

Si usted no espere hasta que fue hecho, tendrá que tener en cuenta los casos en los que otros hilos pueden referirse al objeto que podría ser ya limpiado antes de que el hilo principal se invoca.

6

Si está en 10.6, también puede usar setCompletionBlock:. Se utiliza la siguiente manera:

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

Para la introducción general sobre los bloques y GCD, this article fue extremadamente útil. Encontré GCD & setCompletionBlock más fácil de leer que NSNotification. Una advertencia es, bueno, ¡solo funciona en 10.6!

+1

Si se utiliza la etiqueta "iPhone", es probable que el asker no esté en 10.6. –

+0

Tienes razón, Alex. Estúpido yo. – Yuji

+0

gracias por la propina. –

40

Actualización: Las colas de envío hacen que publicar una notificación en el hilo principal sea muy fácil.

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

que esperar a que los manipuladores de notificación a fin, basta con sustituir dispatch_async con dispatch_sync.


Tras la respuesta de notnoop, aquí es parte de la infraestructura que puede utilizar para colocar de forma segura sus notificaciones en el hilo principal y sin esperar a que termine. ¡Espero que alguien lo encuentre útil!

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 
+1

Muy agradable. Gracias por tomarse el tiempo para escribir este código. –

5

Para ampliar la respuesta de Danra aquí está la versión compatible con ARC de la categoría que arme:

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 + Hilos.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 
+0

me queda bien. Gracias, Oliver! – Elliot

Cuestiones relacionadas