Вопрос

У меня есть NSOperation.По завершении я запускаю NSNotificationCenter, чтобы сообщить программе, что NSoperation завершена, и обновить графический интерфейс.

Насколько я понимаю, слушатели NSNotification не будут работать в основном потоке, потому что NSOperation не находится в основном потоке.

Как я могу сделать так, чтобы слушатели запускались в основном потоке, когда я запускаю свое событие?

[[NSNotificationCenter defaultCenter] postNotificationName:@"myEventName" object:self]; 
Это было полезно?

Решение

Вы можете использовать performSelectorOnMainThread:withObject:waitUntilDone: с использованием вспомогательного метода аналогично следующему примеру.

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

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

Если вы не дожидаетесь завершения, вам нужно будет рассмотреть случаи, когда другие потоки могут ссылаться на объект, который уже может быть очищен до вызова основного потока.

Другие советы

Обновлять:Очереди отправки упрощают публикацию уведомления в основном потоке.

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

Чтобы дождаться завершения работы обработчиков уведомлений, просто замените диспетчерскую_async на диспетчерскую_синхронизацию.


Следуя ответу notnoop, вот некоторая инфраструктура, которую вы можете использовать для безопасной публикации уведомлений в основном потоке. без ждем, пока они закончатся.Надеюсь, кто-то найдет это полезным!

НСНотификатионцентр+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

НСИнвокация+Utils.h:

@interface NSInvocation (Utils)

-(void)invokeOnMainThreadWaitUntilDone:(BOOL)wait;

@end

НСИнвокация+Utils.m:

@implementation NSInvocation (Utils)

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

@end

Если у вас версия 10.6, вы также можете использовать УстановитьКомплетионБлок:.Он используется следующим образом:

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

Для общего ознакомления с блоками и НОД: Эта статья был чрезвычайно полезен.Я обнаружил, что GCD и setCompletionBlock легче читать, чем NSNotification.Одно предостережение: оно работает только на 10.6!

Чтобы расширить ответ Данры, вот совместимая с ARC версия категории, которую я собрал:

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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top