Pregunta

Tengo una NSOperation. Cuando es que el fuego terminada una NSNotificationCenter a dejar que el programa saben que el NSOperation está terminado y para actualizar la interfaz gráfica de usuario.

A mis oyentes entender a los NSNotification no se ejecutará en el hilo principal porque el NSOperation no está en el hilo principal.

¿Cómo puedo hacer para que los oyentes se ejecutan en el hilo principal cuando se disparó mi evento?

[[NSNotificationCenter defaultCenter] postNotificationName:@"myEventName" object:self]; 
¿Fue útil?

Solución

Se 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.

Otros consejos

Actualización: colas de despacho hacen que la publicación de una notificación en el hilo principal muy fácil.

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

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


Tras la respuesta de notnoop, aquí hay algo de la infraestructura se puede utilizar para colocar de forma segura sus notificaciones en el hilo principal sin esperando por ellos hasta el final. Esperemos que alguien encuentre útil esta información!

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 se encuentra en 10.6, también se puede utilizar setCompletionBlock: . Se utiliza como esto:

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 bloques y GCD, este artículo fue extremadamente útil. He encontrado GCD y setCompletionBlock fácil de leer que NSNotification. Una advertencia es, así, que sólo se ejecuta en un 10,6!

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 + 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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top